From f2ad9b27bbaec2adafdbf499eee750830a762d9d Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Thu, 09 Jan 2020 17:56:49 +0800 Subject: [PATCH] Add fl2440 linux-bsp folders --- linux-bsp/asm-study/myboot/include/common.h | 52 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c | 281 linux-bsp/asm-study/myboot/crc32.c | 218 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c | 124 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h | 44 linux-bsp/driver/test/test_s3c_led.c | 81 linux-bsp/asm-study/yaffs2/bsp/makefile | 102 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h | 28 linux-bsp/driver/s3c_led.c | 281 linux-bsp/asm-study/yaffs2/common/malloc.h | 947 + linux-bsp/asm-study/myboot/include/rsa.h | 208 linux-bsp/asm-study/asm/asm_c_buzzer/beep.c | 41 linux-bsp/asm-study/asm/asm_c_led/led.lds | 29 linux-bsp/driver/Makefile | 46 linux-bsp/asm-study/asm/c_led/led.c | 58 linux-bsp/asm-study/myboot/nand.h | 271 linux-bsp/asm-study/myboot/led_beep.c | 56 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h | 43 linux-bsp/asm-study/myboot/serial.c | 74 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c | 58 linux-bsp/asm-study/myboot/xmodem.c | 121 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c | 170 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c | 529 linux-bsp/patches/gen_patch.sh | 71 linux-bsp/asm-study/myboot/include/linux/stddef.h | 18 linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h | 55 linux-bsp/asm-study/myboot/include/linux/string.h | 89 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h | 44 linux-bsp/asm-study/yaffs2/common/makefile | 97 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h | 35 linux-bsp/asm-study/asm/asm_c_led/start.S | 75 linux-bsp/asm-study/yaffs2/bootstrap.lds | 32 linux-bsp/driver/x86/Makefile | 29 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c | 357 linux-bsp/driver/kernel_hello.c | 35 linux-bsp/driver/test/test_plat_key.c | 279 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h | 30 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c | 53 linux-bsp/asm-study/yaffs2/bootstrap.c | 202 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h | 35 linux-bsp/asm-study/asm/c_led/makefile | 51 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h | 24 linux-bsp/driver/test/test_plat_led.c | 72 linux-bsp/asm-study/myboot/include/bignum.h | 380 linux-bsp/asm-study/yaffs2/common/stdio.h | 32 linux-bsp/asm-study/asm/asm_c_led/led.c | 77 linux-bsp/bootstrap/bootstrap.h | 148 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h | 126 linux-bsp/asm-study/myboot/include/nand.h | 271 linux-bsp/asm-study/yaffs2/makefile | 104 linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c | 97 linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c | 3461 ++++ linux-bsp/asm-study/myboot/include/asm/sizes.h | 52 linux-bsp/asm-study/yaffs2/yaffs2/makefile | 97 linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch | 190 linux-bsp/driver/platdrv_led.c | 297 linux-bsp/asm-study/myboot/bootstrap.c | 122 linux-bsp/asm-study/myboot/include/bn_asm.h | 549 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c | 313 linux-bsp/asm-study/myboot/bignum.c | 1842 ++ linux-bsp/asm-study/myboot/bootstrap.lds | 32 linux-bsp/bootstrap/bootstrap.S | 156 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h | 37 linux-bsp/asm-study/myboot/include/s3c24x0.h | 1125 + linux-bsp/asm-study/myboot/rsa.c | 602 linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h | 233 linux-bsp/asm-study/asm/asm_led/led.S | 93 linux-bsp/asm-study/yaffs2/common/types.h | 99 linux-bsp/driver/platdev_led.h | 67 linux-bsp/build.sh | 293 linux-bsp/driver/platdev_led.c | 111 linux-bsp/patches/u-boot-2010.09-fl2440.patch | 2075 ++ linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch | 1765 ++ linux-bsp/asm-study/asm/asm_c_key_led/makefile | 51 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h | 57 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c | 144 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h | 39 linux-bsp/asm-study/yaffs2/bsp/s3c2440.h | 646 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h | 977 + linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c | 473 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h | 33 linux-bsp/asm-study/myboot/include/asm/posix_types.h | 80 linux-bsp/asm-study/myboot/include/asm/hardware.h | 43 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c | 1532 ++ linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c | 5053 ++++++ linux-bsp/asm-study/myboot/include/linux/bitops.h | 75 linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h | 318 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c | 163 linux-bsp/asm-study/myboot/include/s3c2440.h | 674 linux-bsp/asm-study/myboot/include/linux/config.h | 6 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h | 13 linux-bsp/asm-study/yaffs2/bsp/s3c_board.c | 213 linux-bsp/patches/linux-3.0-fl2440.patch | 4153 +++++ linux-bsp/asm-study/asm/asm_c_key_led/key.lds | 29 linux-bsp/asm-study/myboot/include/asm/types.h | 53 linux-bsp/asm-study/yaffs2/bsp/s3c_board.h | 34 linux-bsp/asm-study/myboot/include/linux/types.h | 131 linux-bsp/asm-study/myboot/interrupt.c | 39 linux-bsp/asm-study/myboot/start.S | 348 linux-bsp/asm-study/asm/asm_c_key_led/start.S | 91 README.md | 2 linux-bsp/asm-study/yaffs2/common/string.c | 603 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c | 120 linux-bsp/bootstrap/build.sh | 52 linux-bsp/asm-study/yaffs2/common/dlmalloc.c | 3320 ++++ linux-bsp/asm-study/yaffs2/common/string.h | 86 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h | 38 linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c | 29 linux-bsp/asm-study/myboot/makefile | 118 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h | 47 linux-bsp/asm-study/asm/asm_c_led/makefile | 51 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c | 197 linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h | 99 linux-bsp/asm-study/myboot/k9f2g08.c | 638 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h | 36 linux-bsp/asm-study/asm/asm_c_buzzer/makefile | 51 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c | 407 linux-bsp/asm-study/asm/asm_c_buzzer/start.S | 39 linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch | 70 linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h | 14 linux-bsp/driver/x86/kernel_hello.c | 1 linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c | 276 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h | 35 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h | 22 linux-bsp/bootstrap/makefile | 55 linux-bsp/driver/test/makefile | 46 linux-bsp/asm-study/myboot/mem_init.S | 170 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c | 422 linux-bsp/driver/platdrv_key.c | 339 linux-bsp/asm-study/asm/c_led/led.lds | 29 linux-bsp/asm-study/myboot/include/config.h | 36 linux-bsp/tarballs/rootfs.tar.bz2 | 0 linux-bsp/asm-study/myboot/common.c | 413 linux-bsp/asm-study/myboot/include/asm/io.h | 330 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h | 33 linux-bsp/asm-study/yaffs2/common/printf.c | 374 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c | 97 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h | 28 linux-bsp/asm-study/asm/asm_led/makefile | 51 linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c | 121 linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch | 91 linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds | 29 linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c | 208 linux-bsp/asm-study/myboot/include/asm/errno.h | 138 linux-bsp/asm-study/myboot/include/linux/time.h | 149 linux-bsp/asm-study/yaffs2/start.S | 60 linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h | 177 linux-bsp/asm-study/myboot/include/linux/ctype.h | 54 linux-bsp/asm-study/myboot/include/linux/posix_types.h | 49 149 files changed, 45,708 insertions(+), 1 deletions(-) diff --git a/README.md b/README.md index 43e567e..f8365c9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ ## fl2440 -FL2440开发板源码 +FL2440 ARM Linux Board BSP and application diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/beep.c b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.c new file mode 100644 index 0000000..5994d44 --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.c @@ -0,0 +1,41 @@ + +/*********************************************************************** + * File: beep.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This C code used to turn buzzer on/off on FL2440 board + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +#define GPBCON (*(unsigned long volatile *)0x56000010) +#define GPBDAT (*(unsigned long volatile *)0x56000014) +#define GPBUP (*(unsigned long volatile *)0x56000018) + +#define BEEP 0 /*Buzzer us GPB0 */ +#define LED0 5 +#define DELAY_TIME 40000000 + +static inline void delay (unsigned long loops) +{ + __asm__ volatile ("1:\n" + "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0" (loops)); +} + +int main(void) +{ + GPBCON = (GPBCON|0x3)&0x1; /* Set GPB0 as GPIO output mode(0x01) */ + GPBUP &= ~1; /* Enable pullup resister */ + + GPBDAT |= 0x560; + while(1) + { + GPBDAT &= ~(1<<BEEP); /* Set Beep GPIO as low level */ + delay(DELAY_TIME); + + GPBDAT |= 1<<BEEP; /* Set Beep GPIO as high level */ + delay(DELAY_TIME); + } +} + diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds new file mode 100644 index 0000000..9f03acd --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_buzzer/beep.lds @@ -0,0 +1,29 @@ + +/*********************************************************************** + * File: beep.lds + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: Cross tool link text, refer to u-boot.lds + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +SECTIONS{ + . = 0x33000000; + .text : { + *(.text) + *(.rodata) + } + + .data ALIGN(4): { + *(.data) + } + + .bss ALIGN(4): { + *(.bss) + } +} diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/makefile b/linux-bsp/asm-study/asm/asm_c_buzzer/makefile new file mode 100644 index 0000000..80b687e --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_buzzer/makefile @@ -0,0 +1,51 @@ +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM and C source code +# * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" +# * +# *********************************************************************** + +BINAME = beep +TEXTBASE = 0x33000000 + +CROSS = /opt/xtools/arm920t/bin/arm-linux- +CC = $(CROSS)gcc +LD = $(CROSS)ld +AR = $(CROSS)ar +OBJCOPY = $(CROSS)objcopy +OBJDUMP = $(CROSS)objdump +STRIP = $(CROSS)strip +READELF = $(CROSS)readelf + +CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDSCRIPT = ${BINAME}.lds +LDFLAGS = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE) + +SRC_C = $(wildcard *.c) +SRC_S = $(wildcard *.S) +OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) +OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) + +OBJ_ALL = $(OBJ_C) $(OBJ_S) + +.PHONY : all +all: ${OBJ_ALL} + ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} + ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin + rm -f *.elf *.o + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: + cp ${BINAME}.bin ~/winxp -f --reply=yes + +clean: + rm -f *.elf *.o + rm -f ${BINAME}.bin diff --git a/linux-bsp/asm-study/asm/asm_c_buzzer/start.S b/linux-bsp/asm-study/asm/asm_c_buzzer/start.S new file mode 100644 index 0000000..0d9b4ab --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_buzzer/start.S @@ -0,0 +1,39 @@ +/*********************************************************************** + * File: start.S + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This ASM used to disable watch dog and interrupt, then call C code to + * turn the buzzer on/off on FL2440 board. + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +#define pWTCON 0x53000000 /* Watch dog register address */ +#define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ +#define INTSUBMSK 0x4A00001C + + .text + .align 2 + .global _start + +_start: + + /* Disable watch dog */ + ldr r0, =pWTCON /*Save pwTCON address in r0*/ + mov r1, #0x0 /*Set r1=0x0*/ + str r1, [r0] /*Move the data in r1 to the address specify by r0*/ + + /* mask all IRQs by setting all bits in the INTMR - default */ + mov r1, #0xffffffff + ldr r0, =INTMSK + str r1, [r0] + + ldr r0, =INTSUBMSK + ldr r1, =0x7fff /*There are 15 bits used in INTSUBMSK on S3C2440*/ + str r1, [r0] + + bl main + +halt_loop: + b halt_loop + diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c b/linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c new file mode 100644 index 0000000..8198332 --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_key_led/buzzer_led.c @@ -0,0 +1,97 @@ + +/*********************************************************************** + * File: buzzer_led.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This C code used to turn buzzer on/off on FL2440 board + * ChangeLog: 1, Release initial version on "Tue Mar 22 21:58:24 CST 2011" + * + ***********************************************************************/ + +#define GPBCON (*(unsigned long volatile *)0x56000010) +#define GPBDAT (*(unsigned long volatile *)0x56000014) +#define GPBUP (*(unsigned long volatile *)0x56000018) + +#define BEEP 0 /* Buzzer use GPB0 */ +#define LED0 5 /* LED0 use GPB5*/ +#define LED1 6 /* LED1 use GPB6*/ +#define LED2 8 /* LED2 use GPB8*/ +#define LED3 10 /* LED3 use GPB10*/ +#define DELAY_TIME 40000000 + +unsigned int led_gpio[4] = {5,6,8,10}; + +static inline void delay (unsigned long loops) +{ + __asm__ volatile ("1:\n" + "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0" (loops)); +} + +void init_led_buzzer(void) +{ + GPBCON = (GPBCON|0x333C03)&0x111401; /* Set GPB0,GPB5,GPB8,GPB10 as GPIO input mode */ + GPBDAT |= 0x560; /* Set GPB0,GPB5,GPB6,GPB8,GPB10 as high level */ +} + +void turn_led_on(int led) +{ + if(led > 3) + return; + + /* Set GPIO port as low level */ + GPBDAT = (GPBDAT & ( ~(1<<led_gpio[led])) ); +} + +/* Turn all LED off */ +void turn_all_led_off(void) +{ + GPBDAT |= 0x560; /* Set GPIO port as high level */ +} + +void turn_beep_on(void) +{ + GPBDAT |= 1<<BEEP; /* Set Beep GPIO as high level, turn beep on */ +} + +void turn_beep_off(void) +{ + GPBDAT &= ~(1<<BEEP); /* Set Beep GPIO as low level, turn beep off */ +} + +void turn_buzzer(int times) +{ + int i; + for(i=0; i<times; i++) + { + + turn_beep_on(); + delay(DELAY_TIME); + + turn_beep_off(); + delay(DELAY_TIME); + } +} + +void turn_led_buzzer_off(void) +{ + turn_all_led_off(); + turn_beep_off(); + + return; +} + +/* Input value $key is passed by start.S + * + * Key2 pressed -> key=0, turn LED0 on, beep for 1 time + * Key3 pressed -> key=1, turn LED1 on, beep for 2 time + * Key4 pressed -> key=2, turn LED2 on, beep for 3 time + * Key5 pressed -> key=3, turn LED3 on, beep for 4 time + */ + +void turn_led_buzzer_on(int key) +{ + turn_led_on(key); /* Set correspond LED on */ + turn_buzzer(key+1); /* Let buzzer beep for $key times */ +} + diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/key.lds b/linux-bsp/asm-study/asm/asm_c_key_led/key.lds new file mode 100644 index 0000000..1291410 --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_key_led/key.lds @@ -0,0 +1,29 @@ + +/*********************************************************************** + * File: key.lds + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: Cross tool link text, refer to u-boot.lds + * ChangeLog: 1, Release initial version on "Tue Mar 22 21:58:24 CST 2011" + * + ***********************************************************************/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +SECTIONS{ + . = 0x33000000; + .text : { + *(.text) + *(.rodata) + } + + .data ALIGN(4): { + *(.data) + } + + .bss ALIGN(4): { + *(.bss) + } +} diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/makefile b/linux-bsp/asm-study/asm/asm_c_key_led/makefile new file mode 100644 index 0000000..fa634ce --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_key_led/makefile @@ -0,0 +1,51 @@ +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM and C source code +# * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" +# * +# *********************************************************************** + +BINAME = key +TEXTBASE = 0x33000000 + +CROSS = /opt/xtools/arm920t/bin/arm-linux- +CC = $(CROSS)gcc +LD = $(CROSS)ld +AR = $(CROSS)ar +OBJCOPY = $(CROSS)objcopy +OBJDUMP = $(CROSS)objdump +STRIP = $(CROSS)strip +READELF = $(CROSS)readelf + +CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDSCRIPT = ${BINAME}.lds +LDFLAGS = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE) + +SRC_C = $(wildcard *.c) +SRC_S = $(wildcard *.S) +OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) +OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) + +OBJ_ALL = $(OBJ_C) $(OBJ_S) + +.PHONY : all +all: ${OBJ_ALL} + ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} + ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin + rm -f *.elf *.o + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: + cp ${BINAME}.bin ~/winxp -f --reply=yes + +clean: + rm -f *.elf *.o + rm -f ${BINAME}.bin diff --git a/linux-bsp/asm-study/asm/asm_c_key_led/start.S b/linux-bsp/asm-study/asm/asm_c_key_led/start.S new file mode 100644 index 0000000..facae67 --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_key_led/start.S @@ -0,0 +1,91 @@ +/*********************************************************************** + * File: start.S + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This ASM used to detect the four keys status, if it's pressed down + * then call the C function to turn the buzzer beep and LED on + * ChangeLog: 1, Release initial version on "Tue Mar 22 21:58:24 CST 2011" + * + ***********************************************************************/ + +#define pWTCON 0x53000000 /* Watch dog register address */ +#define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ +#define INTSUBMSK 0x4A00001C + +#define GPFCON 0x56000050 +#define GPFDAT 0x56000054 +#define GPFUP 0x56000058 + +#define KEY2 0 /*KEY S2 use GPF0/EINT0 port*/ +#define KEY3 2 /*KEY S3 use GPF2/EINT2 port*/ +#define KEY4 3 /*KEY S4 use GPF3/EINT3 port*/ +#define KEY5 4 /*KEY S5 use GPF4/EINT4 port*/ + + .text + .align 2 + .global _start + +_start: + + /* Disable watch dog */ + ldr r0, =pWTCON /*Save pwTCON address in r0*/ + mov r1, #0x0 /*Set r1=0x0*/ + str r1, [r0] /*Move the data in r1 to the address specify by r0*/ + + /* mask all IRQs by setting all bits in the INTMR - default */ + mov r1, #0xffffffff + ldr r0, =INTMSK + str r1, [r0] + + ldr r0, =INTSUBMSK + ldr r1, =0x7fff /*There are 15 bits used in INTSUBMSK on S3C2440*/ + str r1, [r0] + + /*Set Beep GPIO port as GPIO input mode*/ + ldr r0, =GPFCON + ldr r1, [r0] + bic r1, r1, #0xf3 /* Set GPF0, GPF2, GPF3, as GPIO input mode(00)*/ + bic r1, r1, #0x0300 /* Set GPF4 as GPIO input mode(00)*/ + str r1, [r0] + + bl init_led_buzzer /*Call C function to init buzzer and LED GPIO port*/ + +loop_detect: + bl turn_led_buzzer_off + + ldr r1, =GPFDAT /*Read the four key GPIO data port*/ + ldr r2, [r1] + + /*Check Key2 pressed down or not*/ + mov r0, #0 /*Turn LED0 on*/ + tst r2, #0x1 + bleq led_beep_on + + /*Check Key3 pressed down or not*/ + mov r0, #1 /*Turn LED1 on*/ + tst r2, #0x4 + bleq led_beep_on + + /*Check Key4 pressed down or not*/ + mov r0, #2 /*Turn LED2 on*/ + tst r2, #0x8 + bleq led_beep_on + + /*Check Key5 pressed down or not*/ + mov r0, #3 /*Turn LED3 on*/ + tst r2, #0x10 + bleq led_beep_on + + /*No key pressed, detect again*/ + b loop_detect + +led_beep_on: + bl turn_led_buzzer_on /*Turn buzzer beep*/ + @mov pc, lr /*Why mov lr, pc can not work?*/ + b loop_detect + + + /*Won't come here*/ +halt_loop: + b halt_loop + diff --git a/linux-bsp/asm-study/asm/asm_c_led/led.c b/linux-bsp/asm-study/asm/asm_c_led/led.c new file mode 100644 index 0000000..e6eb013 --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_led/led.c @@ -0,0 +1,77 @@ + +/*********************************************************************** + * File: led.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This C code used to turn LED0~LED4 on on FL2440 board + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +#define GPBCON (*(unsigned long volatile *)0x56000010) +#define GPBDAT (*(unsigned long volatile *)0x56000014) +#define GPBUP (*(unsigned long volatile *)0x56000018) + +#define LED0 5 /*LED0 use GPB5*/ +#define LED1 6 /*LED1 use GPB6*/ +#define LED2 8 /*LED2 use GPB8*/ +#define LED3 10 /*LED3 use GPB10*/ + +#define DELAY_TIME 1000000 + +static inline void delay (unsigned long loops) +{ + __asm__ volatile ("1:\n" + "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0" (loops)); +} + +void led_init(void) +{ + /* Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ + GPBCON = (GPBCON|0x333C00)&0x111400; + GPBUP = (GPBUP | 0x560); + /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ + GPBDAT = (GPBDAT | 0x560); +} + +int main(void) +{ + led_init(); + while(1) + { + /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ + GPBDAT = (GPBDAT | 0x560); + delay(DELAY_TIME); + + /* Turn LED0 on */ + GPBDAT = (GPBDAT & (~(1<<LED0)) ); + delay(DELAY_TIME); + + /* Turn LED1 on */ + GPBDAT = (GPBDAT & (~(1<<LED1)) ); + delay(DELAY_TIME); + + /* Turn LED2 on */ + GPBDAT = (GPBDAT & (~(1<<LED2)) ); + delay(DELAY_TIME); + + /* Turn LED3 on */ + GPBDAT = (GPBDAT & (~(1<<LED3)) ); + delay(DELAY_TIME); + } +} + +void turn_led_on(int led) +{ + GPBDAT = (GPBDAT & (~(1<<led)) ); + delay(DELAY_TIME); +} + +void turn_led_off(int led) +{ + /* Turn LED0 on */ + GPBDAT = (GPBDAT | (1<<led) ); + delay(DELAY_TIME); +} + diff --git a/linux-bsp/asm-study/asm/asm_c_led/led.lds b/linux-bsp/asm-study/asm/asm_c_led/led.lds new file mode 100644 index 0000000..77023e5 --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_led/led.lds @@ -0,0 +1,29 @@ + +/*********************************************************************** + * File: led.lds + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: Cross tool link text, refer to u-boot.lds + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +SECTIONS{ + . = 0x33000000; + .text : { + *(.text) + *(.rodata) + } + + .data ALIGN(4): { + *(.data) + } + + .bss ALIGN(4): { + *(.bss) + } +} diff --git a/linux-bsp/asm-study/asm/asm_c_led/makefile b/linux-bsp/asm-study/asm/asm_c_led/makefile new file mode 100644 index 0000000..7d190b4 --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_led/makefile @@ -0,0 +1,51 @@ +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM and C source code +# * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" +# * +# *********************************************************************** + +BINAME = led +TEXTBASE = 0x33000000 + +CROSS = /opt/xtools/arm920t/bin/arm-linux- +CC = $(CROSS)gcc +LD = $(CROSS)ld +AR = $(CROSS)ar +OBJCOPY = $(CROSS)objcopy +OBJDUMP = $(CROSS)objdump +STRIP = $(CROSS)strip +READELF = $(CROSS)readelf + +CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDSCRIPT = ${BINAME}.lds +LDFLAGS = -nostartfiles -T $(LDSCRIPT) -Ttext $(TEXTBASE) + +SRC_C = $(wildcard *.c) +SRC_S = $(wildcard *.S) +OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) +OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) + +OBJ_ALL = $(OBJ_C) $(OBJ_S) + +.PHONY : all +all: ${OBJ_ALL} + ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} + ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin + rm -f *.elf *.o + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: + cp ${BINAME}.bin ~/winxp -f --reply=yes + +clean: + rm -f *.elf *.o + rm -f ${BINAME}.bin diff --git a/linux-bsp/asm-study/asm/asm_c_led/start.S b/linux-bsp/asm-study/asm/asm_c_led/start.S new file mode 100644 index 0000000..031b07a --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_c_led/start.S @@ -0,0 +1,75 @@ +/*********************************************************************** + * File: start.S + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This ASM used to disable watch dog and interrupt, then call C code to + * turn the four LEDs on/off on FL2440 board. + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +#define pWTCON 0x53000000 /* Watch dog register address */ +#define INTMSK 0x4A000008 /* Interupt-Controller base addresses */ +#define INTSUBMSK 0x4A00001C + +#define LED0 5 /*LED0 use GPB5*/ +#define LED1 6 /*LED1 use GPB6*/ +#define LED2 8 /*LED2 use GPB8*/ +#define LED3 10 /*LED3 use GPB10*/ + + + .text + .align 2 + .global _start + +_start: + + /* Disable watch dog */ + ldr r0, =pWTCON /*Save pwTCON address in r0*/ + mov r1, #0x0 /*Set r1=0x0*/ + str r1, [r0] /*Move the data in r1 to the address specify by r0*/ + + + /* mask all IRQs by setting all bits in the INTMR - default */ + mov r1, #0xffffffff + ldr r0, =INTMSK + str r1, [r0] + + ldr r0, =INTSUBMSK + ldr r1, =0x7fff /*There are 15 bits used in INTSUBMSK on S3C2440*/ + str r1, [r0] + + bl led_init + +loop: + mov r0,#LED0 + bl turn_led_on + + mov r0,#LED1 + bl turn_led_on + + mov r0,#LED2 + bl turn_led_on + + mov r0,#LED3 + bl turn_led_on + + mov r0,#LED0 + bl turn_led_off + + mov r0,#LED1 + bl turn_led_off + + mov r0,#LED2 + bl turn_led_off + + mov r0,#LED3 + bl turn_led_off + + b loop + + @bl main + +halt_loop: + b halt_loop + diff --git a/linux-bsp/asm-study/asm/asm_led/led.S b/linux-bsp/asm-study/asm/asm_led/led.S new file mode 100644 index 0000000..7fd3fcd --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_led/led.S @@ -0,0 +1,93 @@ +/*********************************************************************** + * File: led.S + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This ASM code used to turn LED0~LED4 on/off on FL2440 board + * ChangeLog: 1, Release initial version on "Sun Mar 20 18:41:04 CST 2011" + * + ***********************************************************************/ + + +#define GPBCON 0x56000010 +#define GPBDAT 0x56000014 +#define GPBUP 0x56000018 + +#define OUTPUT 0x01 /*Set GPIO port as output mode*/ +#define INPUT 0x00 /*Set GPIO port as input mode*/ + +#define BEEP 0 /*On FL2440 board, LED0 use GPB0*/ +#define LED0 5 /*On FL2440 board, LED0 use GPB5*/ +#define LED1 6 /*On FL2440 board, LED0 use GPB6*/ +#define LED2 8 /*On FL2440 board, LED0 use GPB8*/ +#define LED3 10 /*On FL2440 board, LED0 use GPB10*/ + +#define DELAY 0X1000000 + + .text + .align 2 + .global _start + +_start: + /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/ + ldr r0, =GPBCON + ldr r1, [r0] + bic r1, r1, #0x3c00 /*Set GPBCON for GPIO5,GPIO6 as 0x00 */ + orr r1, r1, #0x1400 /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/ + bic r1, r1, #0x00330000 /*Set GPBCON for GPIO8,GPIO10 as 0x00*/ + orr r1, r1, #0x00110000 /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/ + str r1, [r0] + + /*Set internal pullup resister*/ + ldr r0, =GPBUP + ldr r1, [r0] + orr r1, r1, #0x0560 /*Set bit 5,6,8,10, disable pullup resister*/ + @bic r1, r1, #0x0560 /*Clear bit 5,6,8,10, enable pullup resister*/ + str r1, [r0] + + +loopled: + /*Turn off LED5, LED6, LED8, LED10*/ + ldr r2, =GPBDAT + ldr r3, [r2] + orr r3, r3, #0x0560 /*Set bit 5,6,8,10 as high level*/ + str r3, [r2] + ldr r0, =DELAY /*Sleep for a while*/ + bl delay + + /*Turn on LED0*/ + ldr r3, [r2] + bic r3, r3, #(1<<LED0) /*Clear bit 5, set GPB5 as low level*/ + str r3, [r2] + ldr r0, =DELAY /*Sleep for a while*/ + bl delay + + /*Turn on LED1*/ + ldr r3, [r2] + bic r3, r3, #(1<<LED1) /*Clear bit 6, set GPB6 as low level*/ + str r3, [r2] + ldr r0, =DELAY /*Sleep for a while*/ + bl delay + + /*Turn on LED2*/ + ldr r3, [r2] + bic r3, r3, #(1<<LED2) /*Clear bit 8, set GPB8 as low level*/ + str r3, [r2] + ldr r0, =DELAY /*Sleep for a while*/ + bl delay + + /*Turn on LED3*/ + ldr r3, [r2] + bic r3, r3, #(1<<LED3) /*Clear bit 10, set GPB10 as low level*/ + str r3, [r2] + ldr r0, =DELAY /*Sleep for a while*/ + bl delay + + + b loopled /*Loop running LED*/ + +delay: + sub r0, r0, #1 + cmp r0, #0x0 + bne delay + mov pc, lr + diff --git a/linux-bsp/asm-study/asm/asm_led/makefile b/linux-bsp/asm-study/asm/asm_led/makefile new file mode 100644 index 0000000..07cbaea --- /dev/null +++ b/linux-bsp/asm-study/asm/asm_led/makefile @@ -0,0 +1,51 @@ +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM and C source code +# * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" +# * +# *********************************************************************** + +BINAME = led +TEXTBASE = 0x33000000 +#TEXTBASE =0 + +CROSS = /opt/xtools/arm920t/bin/arm-linux- +CC = $(CROSS)gcc +LD = $(CROSS)ld +AR = $(CROSS)ar +OBJCOPY = $(CROSS)objcopy +OBJDUMP = $(CROSS)objdump +STRIP = $(CROSS)strip +READELF = $(CROSS)readelf + +CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDFLAGS = -Ttext $(TEXTBASE) + +SRC_C = $(wildcard *.c) +SRC_S = $(wildcard *.S) +OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) +OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) + +OBJ_ALL = $(OBJ_C) $(OBJ_S) + +.PHONY : all +all: ${OBJ_ALL} + ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} + ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin + rm -f *.elf *.o + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: + cp ${BINAME}.bin ~/winxp -f --reply=yes + +clean: + rm -f *.elf *.o + rm -f ${BINAME}.bin diff --git a/linux-bsp/asm-study/asm/c_led/led.c b/linux-bsp/asm-study/asm/c_led/led.c new file mode 100644 index 0000000..2043ed0 --- /dev/null +++ b/linux-bsp/asm-study/asm/c_led/led.c @@ -0,0 +1,58 @@ + +/*********************************************************************** + * File: led.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This C code used to turn LED0~LED4 on on FL2440 board + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +#define GPBCON (*(unsigned long volatile *)0x56000010) +#define GPBDAT (*(unsigned long volatile *)0x56000014) +#define GPBUP (*(unsigned long volatile *)0x56000018) + +#define LED0 5 /*LED0 use GPB5*/ +#define LED1 6 /*LED1 use GPB6*/ +#define LED2 8 /*LED2 use GPB8*/ +#define LED3 10 /*LED3 use GPB10*/ + +#define DELAY_TIME 20000000 + +static inline void delay (unsigned long loops) +{ + __asm__ volatile ("1:\n" + "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0" (loops)); +} + +int main(void) +{ + /* Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ + GPBCON = (GPBCON|0x333C00)&0x111400; + GPBUP = (GPBUP | 0x560); + + while(1) + { + /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ + GPBDAT = (GPBDAT | 0x560); + delay(DELAY_TIME); + + /* Turn LED0 on */ + GPBDAT = (GPBDAT & (~(1<<LED0)) ); + delay(DELAY_TIME); + + /* Turn LED1 on */ + GPBDAT = (GPBDAT & (~(1<<LED1)) ); + delay(DELAY_TIME); + + /* Turn LED2 on */ + GPBDAT = (GPBDAT & (~(1<<LED2)) ); + delay(DELAY_TIME); + + /* Turn LED3 on */ + GPBDAT = (GPBDAT & (~(1<<LED3)) ); + delay(DELAY_TIME); + } +} + diff --git a/linux-bsp/asm-study/asm/c_led/led.lds b/linux-bsp/asm-study/asm/c_led/led.lds new file mode 100644 index 0000000..2e497ba --- /dev/null +++ b/linux-bsp/asm-study/asm/c_led/led.lds @@ -0,0 +1,29 @@ + +/*********************************************************************** + * File: led.lds + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: Cross tool link text, refer to u-boot.lds + * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" + * + ***********************************************************************/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(main) + +SECTIONS{ + . = 0x33000000; + .text : { + *(.text) + *(.rodata) + } + + .data ALIGN(4): { + *(.data) + } + + .bss ALIGN(4): { + *(.bss) + } +} diff --git a/linux-bsp/asm-study/asm/c_led/makefile b/linux-bsp/asm-study/asm/c_led/makefile new file mode 100644 index 0000000..a07273f --- /dev/null +++ b/linux-bsp/asm-study/asm/c_led/makefile @@ -0,0 +1,51 @@ +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM and C source code +# * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" +# * +# *********************************************************************** + +BINAME = led +TEXTBASE = 0x33000000 + +CROSS = /opt/xtools/arm920t/bin/arm-linux- +CC = $(CROSS)gcc +LD = $(CROSS)ld +AR = $(CROSS)ar +OBJCOPY = $(CROSS)objcopy +OBJDUMP = $(CROSS)objdump +STRIP = $(CROSS)strip +READELF = $(CROSS)readelf + +CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDSCRIPT = ${BINAME}.lds +LDFLAGS = -T $(LDSCRIPT) -Ttext $(TEXTBASE) + +SRC_C = $(wildcard *.c) +SRC_S = $(wildcard *.S) +OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) +OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) + +OBJ_ALL = $(OBJ_C) $(OBJ_S) + +.PHONY : all +all: ${OBJ_ALL} + ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} + ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin + rm -f *.elf *.o + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: + cp ${BINAME}.bin ~/winxp -f --reply=yes + +clean: + rm -f *.elf *.o + rm -f ${BINAME}.bin diff --git a/linux-bsp/asm-study/myboot/bignum.c b/linux-bsp/asm-study/myboot/bignum.c new file mode 100644 index 0000000..7e6ce77 --- /dev/null +++ b/linux-bsp/asm-study/myboot/bignum.c @@ -0,0 +1,1842 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006 Christophe Devine + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +/* + * This MPI implementation is based on: + * + * http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + * http://math.libtomcrypt.com/files/tommath.pdf + */ + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif +#include <common.h> +#include <bignum.h> + +/* + * Bits/chars to # of limbs conversion + */ +#define BITS_TO_LIMBS(i) (((i) + biL - 1) / biL) +#define CHARS_TO_LIMBS(i) (((i) + ciL - 1) / ciL) + +/* + * Initialize one or more mpi + */ +void mpi_init( mpi *X, ... ) +{ + va_list args; + + va_start( args, X ); + + while( X != NULL ) + { + memset( X, 0, sizeof( mpi ) ); + X = va_arg( args, mpi* ); + } + + va_end( args ); +} + +/* + * Unallocate one or more mpi + */ +void mpi_free( mpi *X, ... ) +{ + va_list args; + + va_start( args, X ); + + while( X != NULL ) + { + if( X->p != NULL ) + { + memset( X->p, 0, X->n * ciL ); + free( X->p ); + } + + memset( X, 0, sizeof( mpi ) ); + + X = va_arg( args, mpi* ); + } + + va_end( args ); +} + +/* + * Enlarge X to the specified # of limbs + */ +int mpi_grow( mpi *X, int nblimbs ) +{ + int n = X->n; + + if( n < nblimbs ) + { + if( X->s == 0 ) + X->s = 1; + + X->n = nblimbs; + X->p = (t_int *) realloc( X->p, X->n * ciL ); + + if( X->p == NULL ) + return( 1 ); + + memset( X->p + n, 0, ( X->n - n ) * ciL ); + } + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mpi_copy( mpi *X, mpi *Y ) +{ + int ret, i; + + if( X == Y ) + return( 0 ); + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + CHK( mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ) +{ + mpi T; + + memcpy( &T, X , sizeof( mpi ) ); + memcpy( X , Y , sizeof( mpi ) ); + memcpy( Y , &T, sizeof( mpi ) ); +} + +/* + * Set value from integer + */ +int mpi_lset( mpi *X, int z ) +{ + int ret; + + CHK( mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( t_int *d, int radix, char c ) +{ + *d = 16; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (t_int) radix ) + return( ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Set value from string + */ +int mpi_read( mpi *X, char *s, int radix ) +{ + int ret, i, j, n; + t_int d; + mpi T; + + if( radix < 2 || radix > 16 ) + return( ERR_MPI_INVALID_PARAMETER ); + + mpi_init( &T, NULL ); + + if( radix == 16 ) + { + n = BITS_TO_LIMBS( strlen(s) << 2 ); + + CHK( mpi_grow( X, n ) ); + CHK( mpi_lset( X, 0 ) ); + + for( i = strlen( s ) - 1, j = 0; i >= 0; i--, j++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + break; + } + + CHK( mpi_get_digit( &d, radix, s[i] ) ); + X->p[j / (ciL * 2)] |= d << ( (j % (ciL * 2)) << 2 ); + } + } + else + { + CHK( mpi_lset( X, 0 ) ); + + for( i = 0; i < (int) strlen( s ); i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + CHK( mpi_get_digit( &d, radix, s[i] ) ); + CHK( mpi_mul_int( &T, X, radix ) ); + CHK( mpi_add_int( X, &T, d ) ); + } + } + +cleanup: + + mpi_free( &T, NULL ); + return( ret ); +} + +/* + * Helper to display the digits high-order first + */ +static int mpi_recurse_showf( mpi *X, int radix, FILE *fout ) +{ + int ret; + t_int r; + + if( radix < 2 || radix > 16 ) + return( ERR_MPI_INVALID_PARAMETER ); + + CHK( mpi_mod_int( &r, X, radix ) ); + CHK( mpi_div_int( X, NULL, X, radix ) ); + + if( mpi_cmp_int( X, 0 ) != 0 ) + CHK( mpi_recurse_showf( X, radix, fout ) ); + + if( fout != NULL ) + fprintf( fout, "%c", ( r < 10 ) ? ( (char) r + 0x30 ) + : ( (char) r + 0x37 ) ); + else + printf( "%c", ( r < 10 ) ? ( (char) r + 0x30 ) + : ( (char) r + 0x37 ) ); + +cleanup: + + return( ret ); +} + +/* + * Print the value of X into fout + */ +int mpi_showf( char *name, mpi *X, int radix, FILE *fout ) +{ + int ret, i, j, k, l; + mpi T; + + if( radix < 2 || radix > 16 ) + return( ERR_MPI_INVALID_PARAMETER ); + + mpi_init( &T, NULL ); + + if( fout != NULL ) + fprintf( fout, "%s%c", name, ( X->s == -1 ) ? '-' : ' ' ); + else + printf( "%s%c", name, ( X->s == -1 ) ? '-' : ' ' ); + + if( radix == 16 ) + { + ret = 0; + + for( i = X->n - 1, l = 0; i >= 0; i-- ) + { + for( j = ciL - 1; j >= 0; j-- ) + { + k = ( X->p[i] >> (j << 3) ) & 0xFF; + + if( k == 0 && l == 0 && (i + j) != 0 ) + continue; + + if( fout != NULL ) + fprintf( fout, "%02X", k ); + else + printf( "%02X", k ); + + l = 1; + } + } + } + else + { + CHK( mpi_copy( &T, X ) ); + CHK( mpi_recurse_showf( &T, radix, fout ) ); + } + + if( fout != NULL ) + fprintf( fout, "\n" ); + else + printf( "\n" ); + +cleanup: + + mpi_free( &T, NULL ); + return( ret ); +} + +/* + * Print the value of X on the console + */ +int mpi_show( char *name, mpi *X, int radix ) +{ + return( mpi_showf( name, X, radix, NULL ) ); +} + +/* + * Import an unsigned value from binary data + */ +int mpi_import( mpi *X, unsigned char *buf, int buflen ) +{ + int ret, i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + CHK( mpi_grow( X, CHARS_TO_LIMBS(buflen - n) ) ); + CHK( mpi_lset( X, 0 ) ); + + for( i = buflen - 1, j = 0; i >= n; i--, j++ ) + X->p[j / ciL] |= (t_int) buf[i] << ((j % ciL ) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export an unsigned value into binary data + */ +int mpi_export( mpi *X, unsigned char *buf, int *buflen ) +{ + int i, j, n, ilen; + + n = ( mpi_size( X ) + 7 ) >> 3; + ilen = n; + + if( *buflen < n ) + { + *buflen = n; + return( ERR_MPI_BUFFER_TOO_SMALL ); + } + //*buflen = ilen; + + + memset( buf, 0, *buflen ); + + for( i = *buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char) (X->p[j / ciL] >> ((j % ciL) << 3)); + + + + return( 0 ); +} + +/* + * Return the actual size in bits (without leading 0s) + */ +int mpi_size( mpi *X ) +{ + int i, j; + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = biL - 1; j >= 0; j-- ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + break; + + return( ( i * biL ) + j + 1 ); +} + +/* + * Return the number of least significant bits + */ +int mpi_lsb( mpi *X ) +{ + int i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < (int) biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mpi_shift_l( mpi *X, int count ) +{ + int ret, i, v0, t1; + t_int r0 = 0, r1; + + v0 = count / biL; + t1 = count & (biL - 1); + + i = mpi_size( X ) + count; + + if( X->n * (int) biL < i ) + CHK( mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n - 1; i >= v0; i-- ) + X->p[i] = X->p[i - v0]; + + for( ; i >= 0; i-- ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mpi_shift_r( mpi *X, int count ) +{ + int i, v0, v1; + t_int r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n - 1; i >= 0; i-- ) + { + r1 = X->p[i] << (biL - v1); + X->p[i] >>= v1; + X->p[i] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mpi_cmp_abs( mpi *X, mpi *Y ) +{ + int i, j; + + for( i = X->n - 1; i >= 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = Y->n - 1; j >= 0; j-- ) + if( Y->p[j] != 0 ) + break; + + if( i < 0 && j < 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i >= 0; i-- ) + { + if( X->p[i] > Y->p[i] ) return( 1 ); + if( X->p[i] < Y->p[i] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_mpi( mpi *X, mpi *Y ) +{ + int i, j; + + for( i = X->n - 1; i >= 0; i-- ) + if( X->p[i] != 0 ) + break; + + for( j = Y->n - 1; j >= 0; j-- ) + if( Y->p[j] != 0 ) + break; + + if( i < 0 && j < 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -X->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i >= 0; i-- ) + { + if( X->p[i] > Y->p[i] ) return( X->s ); + if( X->p[i] < Y->p[i] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mpi_cmp_int( mpi *X, int z ) +{ + mpi Y; + t_int p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mpi_add_abs( mpi *X, mpi *A, mpi *B ) +{ + int ret, i, j; + t_int *o, *p, c; + + if( X == B ) + { + mpi *T = A; A = X; B = T; + } + + if( X != A ) + CHK( mpi_copy( X, A ) ); + + for( j = B->n - 1; j >= 0; j-- ) + if( B->p[j] != 0 ) + break; + + CHK( mpi_grow( X, j + 1 ) ); + + o = B->p; p = X->p; c = 0; + + for( i = 0; i <= j; i++, o++, p++ ) + { + *p += c; c = ( *p < c ); + *p += *o; c += ( *p < *o ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + CHK( mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mpi substraction + */ +static void mpi_sub_hlp( int n, t_int *s, t_int *d ) +{ + int i; + t_int c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned substraction: X = |A| - |B| (HAC 14.9) + */ +int mpi_sub_abs( mpi *X, mpi *A, mpi *B ) +{ + mpi TB; + int ret, n; + + if( mpi_cmp_abs( A, B ) < 0 ) + return( ERR_MPI_NEGATIVE_VALUE ); + + mpi_init( &TB, NULL ); + + if( X == B ) + { + CHK( mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + CHK( mpi_copy( X, A ) ); + + ret = 0; + + for( n = B->n - 1; n >= 0; n-- ) + if( B->p[n] != 0 ) + break; + + mpi_sub_hlp( n + 1, B->p, X->p ); + +cleanup: + + mpi_free( &TB, NULL ); + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mpi_add_mpi( mpi *X, mpi *A, mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed substraction: X = A - B + */ +int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mpi_cmp_abs( A, B ) >= 0 ) + { + CHK( mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + CHK( mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + CHK( mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mpi_add_int( mpi *X, mpi *A, int b ) +{ + mpi _B; + t_int p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed substraction: X = A - b + */ +int mpi_sub_int( mpi *X, mpi *A, int b ) +{ + mpi _B; + t_int p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mpi multiplication + */ +static void mpi_mul_hlp( int i, t_int *s, t_int *d, t_int b ) +{ + t_int c = 0; + +#if defined(MULADDC_HUIT) + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } + +#else + if( i == 32 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + else + { + if( i == 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + else + { + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } + } + } +#endif + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mpi_mul_mpi( mpi *X, mpi *A, mpi *B ) +{ + int ret, i, j; + mpi TA, TB; + + mpi_init( &TA, &TB, NULL ); + + if( X == A ) { CHK( mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { CHK( mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n - 1; i >= 0; i-- ) + if( A->p[i] != 0 ) + break; + + for( j = B->n - 1; j >= 0; j-- ) + if( B->p[j] != 0 ) + break; + + CHK( mpi_grow( X, i + j + 2 ) ); + CHK( mpi_lset( X, 0 ) ); + + for( i++; j >= 0; j-- ) + mpi_mul_hlp( i, A->p, X->p + j, B->p[j] ); + + X->s = A->s * B->s; + +cleanup: + + mpi_free( &TB, &TA, NULL ); + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mpi_mul_int( mpi *X, mpi *A, t_int b ) +{ + mpi _B; + t_int p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Division by mpi: A = Q * B + R (HAC 14.20) + */ +int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B ) +{ + int ret, i, n, t, k; + mpi X, Y, Z, T1, T2; + + if( mpi_cmp_int( B, 0 ) == 0 ) + return( ERR_MPI_DIVISION_BY_ZERO ); + + mpi_init( &X, &Y, &Z, &T1, &T2, NULL ); + + if( mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) CHK( mpi_lset( Q, 0 ) ); + if( R != NULL ) CHK( mpi_copy( R, A ) ); + return( 0 ); + } + + CHK( mpi_copy( &X, A ) ); + CHK( mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + CHK( mpi_grow( &Z, A->n + 2 ) ); + CHK( mpi_lset( &Z, 0 ) ); + CHK( mpi_grow( &T1, 2 ) ); + CHK( mpi_grow( &T2, 3 ) ); + + k = mpi_size( &Y ) % biL; + if( k < (int) biL - 1 ) + { + k = biL - 1 - k; + CHK( mpi_shift_l( &X, k ) ); + CHK( mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + mpi_shift_l( &Y, biL * (n - t) ); + while( mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + mpi_sub_mpi( &X, &X, &Y ); + } + mpi_shift_r( &Y, biL * (n - t) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { +#if defined(HAVE_LONGLONG) + t_dbl r; + + r = (t_dbl) X.p[i] << biL; + r |= (t_dbl) X.p[i - 1]; + r /= Y.p[t]; + if( r > ((t_dbl) 1 << biL) - 1) + r = ((t_dbl) 1 << biL) - 1; + + Z.p[i - t - 1] = (t_int) r; +#else + /* + * __udiv_qrnnd_c, from GMP/longlong.h + */ + t_int q0, q1, r0, r1; + t_int d0, d1, d, m; + + d = Y.p[t]; + d0 = ( d << biH ) >> biH; + d1 = ( d >> biH ); + + q1 = X.p[i] / d1; + r1 = X.p[i] - d1 * q1; + r1 <<= biH; + r1 |= ( X.p[i - 1] >> biH ); + + m = q1 * d0; + if( r1 < m ) + { + q1--, r1 += d; + while( r1 >= d && r1 < m ) + q1--, r1 += d; + } + r1 -= m; + + q0 = r1 / d1; + r0 = r1 - d1 * q0; + r0 <<= biH; + r0 |= ( X.p[i - 1] << biH ) >> biH; + + m = q0 * d0; + if( r0 < m ) + { + q0--, r0 += d; + while( r0 >= d && r0 < m ) + q0--, r0 += d; + } + r0 -= m; + + Z.p[i - t - 1] = ( q1 << biH ) | q0; +#endif + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + CHK( mpi_lset( &T1, 0 ) ); + T1.p[0] = (t < 1) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + CHK( mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + CHK( mpi_lset( &T2, 0 ) ); + T2.p[0] = (i < 2) ? 0 : X.p[i - 2]; + T2.p[1] = (i < 1) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + CHK( mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + CHK( mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mpi_cmp_int( &X, 0 ) < 0 ) + { + CHK( mpi_copy( &T1, &Y ) ); + CHK( mpi_shift_l( &T1, biL * (i - t - 1) ) ); + CHK( mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + mpi_copy( Q, &Z ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + mpi_shift_r( &X, k ); + mpi_copy( R, &X ); + + R->s = A->s; + if( mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mpi_free( &X, &Y, &Z, &T1, &T2, NULL ); + return( ret ); +} + +/* + * Division by int: A = Q * b + R + * + * Returns 0 if successful + * 1 if memory allocation failed + * ERR_MPI_DIVISION_BY_ZERO if b == 0 + */ +int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b ) +{ + mpi _B; + t_int p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mpi_mod_mpi( mpi *R, mpi *A, mpi *B ) +{ + int ret; + + CHK( mpi_div_mpi( NULL, R, A, B ) ); + + while( mpi_cmp_int( R, 0 ) < 0 ) + CHK( mpi_add_mpi( R, R, B ) ); + + while( mpi_cmp_mpi( R, B ) >= 0 ) + CHK( mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mpi_mod_int( t_int *r, mpi *A, int b ) +{ + int i; + t_int x, y, z; + + if( b == 0 ) + return( ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + b = -b; + + /* + * handle trivial cases + */ + if( b == 1 ) { *r = 0; return( 0 ); } + if( b == 2 ) { *r = A->p[0] & 1; return( 0 ); } + + /* + * general case + */ + for( i = A->n - 1, y = 0; i >= 0; i-- ) + { + x = A->p[i]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( t_int *mm, mpi *N ) +{ + t_int x, m0 = N->p[0]; + + x = m0; + x += ((m0 + 2) & 4) << 1; + x *= (2 - (m0 * x)); + + if( biL >= 16 ) x *= (2 - (m0 * x)); + if( biL >= 32 ) x *= (2 - (m0 * x)); + if( biL >= 64 ) x *= (2 - (m0 * x)); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static void mpi_montmul( mpi *A, mpi *B, mpi *N, t_int mm, mpi *T ) +{ + int i, n, m; + t_int u0, u1, *d; + + memset( T->p, 0, ciL * T->n ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, ciL * (n + 1) ); + + if( mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static void mpi_montred( mpi *A, mpi *N, t_int mm, mpi *T ) +{ + t_int z = 1; + mpi U; + + U.n = U.s = z; + U.p = &z; + + mpi_montmul( A, &U, N, mm, T ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR ) +{ + int ret, i, j, wsize, wbits; + int bufsize, nblimbs, nbits; + t_int ei, mm, state; + mpi RR, T, W[64]; + + if( mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( ERR_MPI_INVALID_PARAMETER ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mpi_init( &RR, &T, NULL ); + memset( W, 0, sizeof( W ) ); + + i = mpi_size( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + j = N->n + 1; + CHK( mpi_grow( X, j ) ); + CHK( mpi_grow( &W[1], j ) ); + CHK( mpi_grow( &T, j * 2 ) ); + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + CHK( mpi_lset( &RR, 1 ) ); + CHK( mpi_shift_l( &RR, N->n * 2 * biL ) ); + CHK( mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mpi_cmp_mpi( A, N ) >= 0 ) + mpi_mod_mpi( &W[1], A, N ); + else mpi_copy( &W[1], A ); + + mpi_montmul( &W[1], &RR, N, mm, &T ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + CHK( mpi_copy( X, &RR ) ); + mpi_montred( X, N, mm, &T ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = 1 << (wsize - 1); + + CHK( mpi_grow( &W[j], N->n + 1 ) ); + CHK( mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + mpi_montmul( &W[j], &W[j], N, mm, &T ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < (1 << wsize); i++ ) + { + CHK( mpi_grow( &W[i], N->n + 1 ) ); + CHK( mpi_copy( &W[i], &W[i - 1] ) ); + + mpi_montmul( &W[i], &W[1], N, mm, &T ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs-- == 0 ) + break; + + bufsize = sizeof( t_int ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + mpi_montmul( X, X, N, mm, &T ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= (ei << (wsize - nbits)); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + mpi_montmul( X, X, N, mm, &T ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + mpi_montmul( X, &W[wbits], N, mm, &T ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + mpi_montmul( X, X, N, mm, &T ); + + wbits <<= 1; + + if( (wbits & (1 << wsize)) != 0 ) + mpi_montmul( X, &W[1], N, mm, &T ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + mpi_montred( X, N, mm, &T ); + +cleanup: + + for( i = (1 << (wsize - 1)); i < (1 << wsize); i++ ) + mpi_free( &W[i], NULL ); + + if( _RR != NULL ) + mpi_free( &W[1], &T, NULL ); + else mpi_free( &W[1], &T, &RR, NULL ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mpi_gcd( mpi *G, mpi *A, mpi *B ) +{ + int ret, count; + mpi TG, TA, TB; + + mpi_init( &TG, &TA, &TB, NULL ); + + CHK( mpi_lset( &TG, 1 ) ); + CHK( mpi_copy( &TA, A ) ); + CHK( mpi_copy( &TB, B ) ); + + TA.s = TB.s = 1; + + count = ( mpi_lsb( &TA ) < mpi_lsb( &TB ) ) + ? mpi_lsb( &TA ) : mpi_lsb( &TB ); + + CHK( mpi_shift_l( &TG, count ) ); + CHK( mpi_shift_r( &TA, count ) ); + CHK( mpi_shift_r( &TB, count ) ); + + while( mpi_cmp_int( &TA, 0 ) != 0 ) + { + while( ( TA.p[0] & 1 ) == 0 ) CHK( mpi_shift_r( &TA, 1 ) ); + while( ( TB.p[0] & 1 ) == 0 ) CHK( mpi_shift_r( &TB, 1 ) ); + + if( mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + CHK( mpi_sub_abs( &TA, &TA, &TB ) ); + CHK( mpi_shift_r( &TA, 1 ) ); + } + else + { + CHK( mpi_sub_abs( &TB, &TB, &TA ) ); + CHK( mpi_shift_r( &TB, 1 ) ); + } + } + + CHK( mpi_mul_mpi( G, &TG, &TB ) ); + +cleanup: + + mpi_free( &TB, &TA, &TG, NULL ); + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mpi_inv_mod( mpi *X, mpi *A, mpi *N ) +{ + int ret; + mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mpi_cmp_int( N, 0 ) <= 0 ) + return( ERR_MPI_INVALID_PARAMETER ); + + mpi_init( &TA, &TU, &U1, &U2, &G, + &TB, &TV, &V1, &V2, NULL ); + + CHK( mpi_gcd( &G, A, N ) ); + + if( mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = ERR_MPI_NOT_INVERTIBLE; + goto cleanup; + } + + CHK( mpi_mod_mpi( &TA, A, N ) ); + CHK( mpi_copy( &TU, &TA ) ); + CHK( mpi_copy( &TB, N ) ); + CHK( mpi_copy( &TV, N ) ); + + CHK( mpi_lset( &U1, 1 ) ); + CHK( mpi_lset( &U2, 0 ) ); + CHK( mpi_lset( &V1, 0 ) ); + CHK( mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + CHK( mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + CHK( mpi_add_mpi( &U1, &U1, &TB ) ); + CHK( mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + CHK( mpi_shift_r( &U1, 1 ) ); + CHK( mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + CHK( mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + CHK( mpi_add_mpi( &V1, &V1, &TB ) ); + CHK( mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + CHK( mpi_shift_r( &V1, 1 ) ); + CHK( mpi_shift_r( &V2, 1 ) ); + } + + if( mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + CHK( mpi_sub_mpi( &TU, &TU, &TV ) ); + CHK( mpi_sub_mpi( &U1, &U1, &V1 ) ); + CHK( mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + CHK( mpi_sub_mpi( &TV, &TV, &TU ) ); + CHK( mpi_sub_mpi( &V1, &V1, &U1 ) ); + CHK( mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mpi_cmp_int( &V1, 0 ) < 0 ) + CHK( mpi_add_mpi( &V1, &V1, N ) ); + + while( mpi_cmp_mpi( &V1, N ) >= 0 ) + CHK( mpi_sub_mpi( &V1, &V1, N ) ); + + CHK( mpi_copy( X, &V1 ) ); + +cleanup: + + mpi_free( &V2, &V1, &TV, &TB, &G, + &U2, &U1, &TU, &TA, NULL ); + + return( ret ); +} + +#if !defined(NO_GENPRIME) +static const int small_prime[] = +{ + 3, 113, 271, 443, 619, 821, 1013, 1213, + 5, 127, 277, 449, 631, 823, 1019, 1217, + 7, 131, 281, 457, 641, 827, 1021, 1223, + 11, 137, 283, 461, 643, 829, 1031, 1229, + 13, 139, 293, 463, 647, 839, 1033, 1231, + 17, 149, 307, 467, 653, 853, 1039, 1237, + 19, 151, 311, 479, 659, 857, 1049, 1249, + 23, 157, 313, 487, 661, 859, 1051, 1259, + 29, 163, 317, 491, 673, 863, 1061, 1277, + 31, 167, 331, 499, 677, 877, 1063, 1279, + 37, 173, 337, 503, 683, 881, 1069, 1283, + 41, 179, 347, 509, 691, 883, 1087, 1289, + 43, 181, 349, 521, 701, 887, 1091, 1291, + 47, 191, 353, 523, 709, 907, 1093, 1297, + 53, 193, 359, 541, 719, 911, 1097, 1301, + 59, 197, 367, 547, 727, 919, 1103, 1303, + 61, 199, 373, 557, 733, 929, 1109, 1307, + 67, 211, 379, 563, 739, 937, 1117, 1319, + 71, 223, 383, 569, 743, 941, 1123, 1321, + 73, 227, 389, 571, 751, 947, 1129, 1327, + 79, 229, 397, 577, 757, 953, 1151, 1361, + 83, 233, 401, 587, 761, 967, 1153, 1367, + 89, 239, 409, 593, 769, 971, 1163, 1373, + 97, 241, 419, 599, 773, 977, 1171, 1381, + 101, 251, 421, 601, 787, 983, 1181, 1399, + 103, 257, 431, 607, 797, 991, 1187, 1409, + 107, 263, 433, 613, 809, 997, 1193, 1423, + 109, 269, 439, 617, 811, 1009, 1201, -110 +}; + +/* + * Miller-Rabin primality test (HAC 4.24) + */ +int mpi_is_prime( mpi *X ) +{ + int ret, i, j, s, xs; + mpi W, R, T, A, RR; + + if( mpi_cmp_int( X, 0 ) == 0 ) + return( 0 ); + + mpi_init( &W, &R, &T, &A, &RR, NULL ); + xs = X->s; X->s = 1; + + /* + * test trivial factors first + */ + if( ( X->p[0] & 1 ) == 0 ) + return( ERR_MPI_IS_COMPOSITE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + t_int r; + + if( mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 0 ); + + CHK( mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( ERR_MPI_IS_COMPOSITE ); + } + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + CHK( mpi_sub_int( &W, X, 1 ) ); + CHK( mpi_copy( &R, &W ) ); + CHK( mpi_shift_r( &R, s = mpi_lsb( &W ) ) ); + + for( i = 0; i < 8; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + CHK( mpi_grow( &A, X->n ) ); + + for( j = 0; j < A.n; j++ ) + A.p[j] = (t_int) rand() * rand(); + + CHK( mpi_shift_r( &A, mpi_size( &A ) - + mpi_size( &W ) + 1 ) ); + A.p[0] |= 3; + + /* + * A = A^R mod |X| + */ + CHK( mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mpi_cmp_mpi( &A, &W ) == 0 || + mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + CHK( mpi_mul_mpi( &T, &A, &A ) ); + CHK( mpi_mod_mpi( &A, &T, X ) ); + + if( mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mpi_cmp_mpi( &A, &W ) != 0 || j < s ) + { + ret = ERR_MPI_IS_COMPOSITE; + break; + } + } + +cleanup: + + X->s = xs; + mpi_free( &A, &T, &R, &W, NULL ); + return( ret ); +} + +/* + * Prime number generation + */ +int mpi_gen_prime( mpi *X, int nbits, int dh_flag, + int (*rng_f)(void *), void *rng_d ) +{ + int ret, k, n; + unsigned char *p; + mpi Y; + + if( nbits < 3 ) + return( ERR_MPI_INVALID_PARAMETER ); + + mpi_init( &Y, NULL ); + + n = BITS_TO_LIMBS( nbits ); + + CHK( mpi_grow( X, n ) ); + CHK( mpi_lset( X, 0 ) ); + + p = (unsigned char *) X->p; + for( k = 0; k < ciL * X->n; k++ ) + *p++ = rng_f( rng_d ); + + k = mpi_size( X ); + if( k < nbits ) CHK( mpi_shift_l( X, nbits - k ) ); + if( k > nbits ) CHK( mpi_shift_r( X, k - nbits ) ); + X->p[0] |= 3; + + if( dh_flag == 0 ) + { + while( ( ret = mpi_is_prime( X ) ) != 0 ) + { + if( ret != ERR_MPI_IS_COMPOSITE ) + goto cleanup; + + CHK( mpi_add_int( X, X, 2 ) ); + } + } + else + { + CHK( mpi_sub_int( &Y, X, 1 ) ); + CHK( mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + if( ( ret = mpi_is_prime( X ) ) == 0 ) + { + if( ( ret = mpi_is_prime( &Y ) ) == 0 ) + break; + + if( ret != ERR_MPI_IS_COMPOSITE ) + goto cleanup; + } + + if( ret != ERR_MPI_IS_COMPOSITE ) + goto cleanup; + + CHK( mpi_add_int( &Y, X, 1 ) ); + CHK( mpi_add_int( X, X, 2 ) ); + CHK( mpi_shift_r( &Y, 1 ) ); + } + } + +cleanup: + + mpi_free( &Y, NULL ); + return( ret ); +} +#endif + +static const char _bignum_src[] = "_bignum_src"; + +#ifdef SELF_TEST +/* + * Checkup routine + */ +int mpi_self_test( void ) +{ + int ret; + mpi A, E, N, X, Y, U, V; + + mpi_init( &A, &E, &N, &X, &Y, &U, &V, NULL ); + + CHK( mpi_read( &A, "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6", 16 ) ); + CHK( mpi_read( &E, "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E", 16 ) ); + CHK( mpi_read( &N, "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5", 16 ) ); + + CHK( mpi_mul_mpi( &X, &A, &N ) ); + CHK( mpi_read( &U, "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E", 16 ) ); + + printf( " MPI test #1 (mul_mpi): " ); + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + printf( "passed\n" ); + + CHK( mpi_div_mpi( &X, &Y, &A, &N ) ); + CHK( mpi_read( &U, "256567336059E52CAE22925474705F39A94", 16 ) ); + CHK( mpi_read( &V, "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642", 16 ) ); + + printf( " MPI test #2 (div_mpi): " ); + if( mpi_cmp_mpi( &X, &U ) != 0 || + mpi_cmp_mpi( &Y, &V ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + printf( "passed\n" ); + + CHK( mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + CHK( mpi_read( &U, "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87", 16 ) ); + + printf( " MPI test #3 (exp_mod): " ); + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + printf( "passed\n" ); + + CHK( mpi_inv_mod( &X, &A, &N ) ); + CHK( mpi_read( &U, "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61", 16 ) ); + + printf( " MPI test #4 (inv_mod): " ); + if( mpi_cmp_mpi( &X, &U ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + printf( "passed\n" ); + +cleanup: + + if( ret != 0 ) + printf( "Unexpected error, return code = %d\n", ret ); + + mpi_free( &V, &U, &Y, &X, &N, &E, &A, NULL ); + + printf( "\n" ); + return( 0 ); +} +#else +int mpi_self_test( void ) +{ + return( 0 ); +} +#endif diff --git a/linux-bsp/asm-study/myboot/bootstrap.c b/linux-bsp/asm-study/myboot/bootstrap.c new file mode 100644 index 0000000..66e8e29 --- /dev/null +++ b/linux-bsp/asm-study/myboot/bootstrap.c @@ -0,0 +1,122 @@ +/******************************************************************************************** + * File: bootstrap.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This C code is the first stage bootloader(named bootstrap) + main code, test on FL2440 board. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#include <common.h> +#include <nand.h> + +int dbg_mode(struct boot_nand_t *nand); +unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[]); + +void print_buf(char *prompt, char *buf, int len) +{ + int i; + printf("%s %d bytes\n", prompt, len); + printf("------------------------------------------------------------------------------------\n"); + for(i=0; i<len; i++) + { + printf("0x%02x ", buf[i]); + if(! (i+1)%32 ) + printf("\n"); + } + + printf("\n"); + printf("------------------------------------------------------------------------------------\n"); +} + + +int bootstrap_main(void) +{ + struct boot_nand_t nand; + char buf[0x20000]; + ulong test_block = 0x0; /*0x1860000 is bad block*/ +// char *addr = (char *)TEXT_BASE; + char *addr = (char *)0x36000000; + + serial_init(); + init_led_beep(); + + printf("\bBootstrap Version 0.0.1\n"); + + turn_led_on(LED0); + + if (nand_init(&nand) < 0) + { + printf("Nandflash init failure.\n"); + return -1; + } + + +#if 0 + nand_scrub(&nand); + + nand_erase(&nand, test_block, 0x20000, SKIP_BAD_BLOCK); + + memset(buf,0x00, sizeof(buf)); + nand_read_spare(&nand, test_block, 64, buf); + print_buf("Spare area read:", buf, 64); + + nand_read(&nand, test_block, nand.page_size, buf); + print_buf("Whole page Write:", buf, nand.page_size); +#endif + +#if 0 + /*Write spare area*/ + memset(buf,0x44,sizeof(buf)); + + nand_write(&nand, test_block, nand.page_size, buf); + nand_read(&nand, test_block, nand.page_size, buf); + print_buf("Whole page Write:", buf, nand.page_size); + + + nand_write_spare(&nand, 0x0000, 64, buf); + nand_read_spare(&nand, test_block, 64, buf); + print_buf("Spare area read:", buf, 64); +#endif + + dbg_mode(&nand); + + nand_read(&nand, LAUNCHER_NAND_ADDR, 1024, addr); + do_go_exec((void *)addr, 0, NULL); + + while (1) + ; + + return 0; +} + + +__attribute__((weak)) +unsigned long do_go_exec (ulong (*entry)(int, char * const []), int argc, char * const argv[]) +{ + printf ("## Starting application at 0x%08lX ...\n", entry); + return entry (argc, argv); +} + +int dbg_mode(struct boot_nand_t *nand) +{ + long size; + char *addr = (char *)TEXT_BASE; + ulong erase_size; + + dbg_print("Comes into bootstrap debug mode and Xmodem wait for receive new launcher:\n"); + + beep(1); + + size = xmodem_recv(addr); + dbg_print("\tBootstrap Receive Launcher file size: %ld bytes\n", size); + + erase_size = (size/nand->block_size + 1)*nand->block_size; + + nand_erase(nand, LAUNCHER_NAND_ADDR, erase_size, SKIP_BAD_BLOCK); + nand_write(nand, LAUNCHER_NAND_ADDR, size, addr); + + return 0; +} + diff --git a/linux-bsp/asm-study/myboot/bootstrap.lds b/linux-bsp/asm-study/myboot/bootstrap.lds new file mode 100644 index 0000000..810e0a7 --- /dev/null +++ b/linux-bsp/asm-study/myboot/bootstrap.lds @@ -0,0 +1,32 @@ +/******************************************************************************************** + * File: bootstrap.lds + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This is the LD linker configure script for bootstrap + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +SECTIONS{ + . = ALIGN(4); + .text : + { + start.o (.text) + *(.text) + } + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + . = ALIGN(4); + .rodata : { *(.rodata) } + . = ALIGN(4); + .data : { *(.data) } + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} + diff --git a/linux-bsp/asm-study/myboot/common.c b/linux-bsp/asm-study/myboot/common.c new file mode 100644 index 0000000..01092f5 --- /dev/null +++ b/linux-bsp/asm-study/myboot/common.c @@ -0,0 +1,413 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include <common.h> + +void * memset(void * s,int c,size_t count) +{ + unsigned long *sl = (unsigned long *) s; + unsigned long cl = 0; + char *s8; + int i; + + /* do it one word at a time (32 bits or 64 bits) while possible */ + if ( ((ulong)s & (sizeof(*sl) - 1)) == 0) { + for (i = 0; i < sizeof(*sl); i++) { + cl <<= 8; + cl |= c & 0xff; + } + while (count >= sizeof(*sl)) { + *sl++ = cl; + count -= sizeof(*sl); + } + } + /* fill 8 bits at a time */ + s8 = (char *)sl; + while (count--) + *s8++ = c; + + return s; +} + +#ifdef CONFIG_PRINTF_DBG + +size_t strnlen(const char *s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */ ; + return sc - s; +} + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i = 0; + + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#ifdef CFG_64BIT_VSPRINTF +#define do_div(n,base) ({ \ + unsigned int __res; \ + __res = ((unsigned long long) n) % base; \ + n = ((unsigned long long) n) / base; \ + __res; \ +}) +#else +#define do_div(n,base) ({ \ + int __res; \ + __res = ((unsigned long) n) % base; \ + n = ((unsigned long) n) / base; \ + __res; \ +}) +#endif + +#ifdef CFG_64BIT_VSPRINTF +static char *number(char *str, long long num, unsigned int base, int size, int precision, int type) +#else +static char *number(char *str, long num, unsigned int base, int size, int precision, int type) +#endif +{ + char c, sign, tmp[66]; + const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + if (type & SPECIAL) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++] = '0'; + else + while (num != 0) + tmp[i++] = digits[do_div(num, base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char *buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; +#ifdef CFG_64BIT_VSPRINTF + unsigned long long num; +#else + unsigned long num; +#endif + int i, base; + char *str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + * number of chars for from string */ + int qualifier; /* 'h', 'l', or 'q' for integer fields */ + + for (str = buf; *fmt; ++fmt) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt == 'Z' || *fmt == 'z' || *fmt == 't' || *fmt == 'q') + { + qualifier = *fmt; + if (qualifier == 'l' && *(fmt + 1) == 'l') + { + qualifier = 'q'; + ++fmt; + } + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), 16, field_width, precision, flags); + continue; + + case 'n': + if (qualifier == 'l') + { + long *ip = va_arg(args, long *); + *ip = (str - buf); + } + else + { + int *ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } +#ifdef CFG_64BIT_VSPRINTF + if (qualifier == 'q') /* "quad" for 64 bit variables */ + num = va_arg(args, unsigned long long); + else +#endif + if (qualifier == 'l') + { + num = va_arg(args, unsigned long); + } + else if (qualifier == 'Z' || qualifier == 'z') + { + num = va_arg(args, size_t); + } + else if (qualifier == 't') + { + num = va_arg(args, ptrdiff_t); + } + else if (qualifier == 'h') + { + num = (unsigned short)va_arg(args, int); + if (flags & SIGN) + num = (short)num; + } + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str - buf; +} + +void printf(const char *fmt, ...) +{ + va_list args; + uint i; + char printbuffer[CFG_PBSIZE]; + + va_start(args, fmt); + + /* For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vsprintf(printbuffer, fmt, args); + va_end(args); + + serial_puts(printbuffer); +} + +int sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + return i; +} +#else +void printf(const char *fmt, ...) +{ + +} +#endif /*Define CONFIG_PRINTF_DBG */ diff --git a/linux-bsp/asm-study/myboot/crc32.c b/linux-bsp/asm-study/myboot/crc32.c new file mode 100644 index 0000000..b87391e --- /dev/null +++ b/linux-bsp/asm-study/myboot/crc32.c @@ -0,0 +1,218 @@ +/* + * This file is derived from crc32.c from the zlib-1.1.3 distribution + * by Jean-loup Gailly and Mark Adler. + */ + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include <common.h> + +#define __cpu_to_le32(x) ((__u32)(x)) +#define cpu_to_le32 __cpu_to_le32 +# define le32_to_cpu(x) (x) + +#define local static +#define ZEXPORT /* empty */ + +#define tole(x) cpu_to_le32(x) + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local uint32_t crc_table[256]; +local void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + 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. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +local void make_crc_table() +{ + uint32_t c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = tole(c); + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ + +local const uint32_t crc_table[256] = { +tole(0x00000000L), tole(0x77073096L), tole(0xee0e612cL), tole(0x990951baL), +tole(0x076dc419L), tole(0x706af48fL), tole(0xe963a535L), tole(0x9e6495a3L), +tole(0x0edb8832L), tole(0x79dcb8a4L), tole(0xe0d5e91eL), tole(0x97d2d988L), +tole(0x09b64c2bL), tole(0x7eb17cbdL), tole(0xe7b82d07L), tole(0x90bf1d91L), +tole(0x1db71064L), tole(0x6ab020f2L), tole(0xf3b97148L), tole(0x84be41deL), +tole(0x1adad47dL), tole(0x6ddde4ebL), tole(0xf4d4b551L), tole(0x83d385c7L), +tole(0x136c9856L), tole(0x646ba8c0L), tole(0xfd62f97aL), tole(0x8a65c9ecL), +tole(0x14015c4fL), tole(0x63066cd9L), tole(0xfa0f3d63L), tole(0x8d080df5L), +tole(0x3b6e20c8L), tole(0x4c69105eL), tole(0xd56041e4L), tole(0xa2677172L), +tole(0x3c03e4d1L), tole(0x4b04d447L), tole(0xd20d85fdL), tole(0xa50ab56bL), +tole(0x35b5a8faL), tole(0x42b2986cL), tole(0xdbbbc9d6L), tole(0xacbcf940L), +tole(0x32d86ce3L), tole(0x45df5c75L), tole(0xdcd60dcfL), tole(0xabd13d59L), +tole(0x26d930acL), tole(0x51de003aL), tole(0xc8d75180L), tole(0xbfd06116L), +tole(0x21b4f4b5L), tole(0x56b3c423L), tole(0xcfba9599L), tole(0xb8bda50fL), +tole(0x2802b89eL), tole(0x5f058808L), tole(0xc60cd9b2L), tole(0xb10be924L), +tole(0x2f6f7c87L), tole(0x58684c11L), tole(0xc1611dabL), tole(0xb6662d3dL), +tole(0x76dc4190L), tole(0x01db7106L), tole(0x98d220bcL), tole(0xefd5102aL), +tole(0x71b18589L), tole(0x06b6b51fL), tole(0x9fbfe4a5L), tole(0xe8b8d433L), +tole(0x7807c9a2L), tole(0x0f00f934L), tole(0x9609a88eL), tole(0xe10e9818L), +tole(0x7f6a0dbbL), tole(0x086d3d2dL), tole(0x91646c97L), tole(0xe6635c01L), +tole(0x6b6b51f4L), tole(0x1c6c6162L), tole(0x856530d8L), tole(0xf262004eL), +tole(0x6c0695edL), tole(0x1b01a57bL), tole(0x8208f4c1L), tole(0xf50fc457L), +tole(0x65b0d9c6L), tole(0x12b7e950L), tole(0x8bbeb8eaL), tole(0xfcb9887cL), +tole(0x62dd1ddfL), tole(0x15da2d49L), tole(0x8cd37cf3L), tole(0xfbd44c65L), +tole(0x4db26158L), tole(0x3ab551ceL), tole(0xa3bc0074L), tole(0xd4bb30e2L), +tole(0x4adfa541L), tole(0x3dd895d7L), tole(0xa4d1c46dL), tole(0xd3d6f4fbL), +tole(0x4369e96aL), tole(0x346ed9fcL), tole(0xad678846L), tole(0xda60b8d0L), +tole(0x44042d73L), tole(0x33031de5L), tole(0xaa0a4c5fL), tole(0xdd0d7cc9L), +tole(0x5005713cL), tole(0x270241aaL), tole(0xbe0b1010L), tole(0xc90c2086L), +tole(0x5768b525L), tole(0x206f85b3L), tole(0xb966d409L), tole(0xce61e49fL), +tole(0x5edef90eL), tole(0x29d9c998L), tole(0xb0d09822L), tole(0xc7d7a8b4L), +tole(0x59b33d17L), tole(0x2eb40d81L), tole(0xb7bd5c3bL), tole(0xc0ba6cadL), +tole(0xedb88320L), tole(0x9abfb3b6L), tole(0x03b6e20cL), tole(0x74b1d29aL), +tole(0xead54739L), tole(0x9dd277afL), tole(0x04db2615L), tole(0x73dc1683L), +tole(0xe3630b12L), tole(0x94643b84L), tole(0x0d6d6a3eL), tole(0x7a6a5aa8L), +tole(0xe40ecf0bL), tole(0x9309ff9dL), tole(0x0a00ae27L), tole(0x7d079eb1L), +tole(0xf00f9344L), tole(0x8708a3d2L), tole(0x1e01f268L), tole(0x6906c2feL), +tole(0xf762575dL), tole(0x806567cbL), tole(0x196c3671L), tole(0x6e6b06e7L), +tole(0xfed41b76L), tole(0x89d32be0L), tole(0x10da7a5aL), tole(0x67dd4accL), +tole(0xf9b9df6fL), tole(0x8ebeeff9L), tole(0x17b7be43L), tole(0x60b08ed5L), +tole(0xd6d6a3e8L), tole(0xa1d1937eL), tole(0x38d8c2c4L), tole(0x4fdff252L), +tole(0xd1bb67f1L), tole(0xa6bc5767L), tole(0x3fb506ddL), tole(0x48b2364bL), +tole(0xd80d2bdaL), tole(0xaf0a1b4cL), tole(0x36034af6L), tole(0x41047a60L), +tole(0xdf60efc3L), tole(0xa867df55L), tole(0x316e8eefL), tole(0x4669be79L), +tole(0xcb61b38cL), tole(0xbc66831aL), tole(0x256fd2a0L), tole(0x5268e236L), +tole(0xcc0c7795L), tole(0xbb0b4703L), tole(0x220216b9L), tole(0x5505262fL), +tole(0xc5ba3bbeL), tole(0xb2bd0b28L), tole(0x2bb45a92L), tole(0x5cb36a04L), +tole(0xc2d7ffa7L), tole(0xb5d0cf31L), tole(0x2cd99e8bL), tole(0x5bdeae1dL), +tole(0x9b64c2b0L), tole(0xec63f226L), tole(0x756aa39cL), tole(0x026d930aL), +tole(0x9c0906a9L), tole(0xeb0e363fL), tole(0x72076785L), tole(0x05005713L), +tole(0x95bf4a82L), tole(0xe2b87a14L), tole(0x7bb12baeL), tole(0x0cb61b38L), +tole(0x92d28e9bL), tole(0xe5d5be0dL), tole(0x7cdcefb7L), tole(0x0bdbdf21L), +tole(0x86d3d2d4L), tole(0xf1d4e242L), tole(0x68ddb3f8L), tole(0x1fda836eL), +tole(0x81be16cdL), tole(0xf6b9265bL), tole(0x6fb077e1L), tole(0x18b74777L), +tole(0x88085ae6L), tole(0xff0f6a70L), tole(0x66063bcaL), tole(0x11010b5cL), +tole(0x8f659effL), tole(0xf862ae69L), tole(0x616bffd3L), tole(0x166ccf45L), +tole(0xa00ae278L), tole(0xd70dd2eeL), tole(0x4e048354L), tole(0x3903b3c2L), +tole(0xa7672661L), tole(0xd06016f7L), tole(0x4969474dL), tole(0x3e6e77dbL), +tole(0xaed16a4aL), tole(0xd9d65adcL), tole(0x40df0b66L), tole(0x37d83bf0L), +tole(0xa9bcae53L), tole(0xdebb9ec5L), tole(0x47b2cf7fL), tole(0x30b5ffe9L), +tole(0xbdbdf21cL), tole(0xcabac28aL), tole(0x53b39330L), tole(0x24b4a3a6L), +tole(0xbad03605L), tole(0xcdd70693L), tole(0x54de5729L), tole(0x23d967bfL), +tole(0xb3667a2eL), tole(0xc4614ab8L), tole(0x5d681b02L), tole(0x2a6f2b94L), +tole(0xb40bbe37L), tole(0xc30c8ea1L), tole(0x5a05df1bL), tole(0x2d02ef8dL) +}; +#endif + +#if 0 +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uint32_t * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uint32_t *)crc_table; +} +#endif + +/* ========================================================================= */ +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define DO_CRC(x) crc = tab[(crc ^ (x)) & 255] ^ (crc >> 8) +# else +# define DO_CRC(x) crc = tab[((crc >> 24) ^ (x)) & 255] ^ (crc << 8) +# endif + +/* ========================================================================= */ + +/* No ones complement version. JFFS2 (and other things ?) + * don't use ones compliment in their CRC calculations. + */ +uint32_t ZEXPORT crc32_no_comp(uint32_t crc, const uchar *buf, uint len) +{ + const uint32_t *tab = crc_table; + const uint32_t *b =(const uint32_t *)buf; + size_t rem_len; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = cpu_to_le32(crc); + /* Align it */ + if (((long)b) & 3 && len) { + uint8_t *p = (uint8_t *)b; + do { + DO_CRC(*p++); + } while ((--len) && ((long)p)&3); + b = (uint32_t *)p; + } + + rem_len = len & 3; + len = len >> 2; + for (--b; len; --len) { + /* load data 32 bits wide, xor data 32 bits wide. */ + crc ^= *++b; /* use pre increment for speed */ + DO_CRC(0); + DO_CRC(0); + DO_CRC(0); + DO_CRC(0); + } + len = rem_len; + /* And the last few bytes */ + if (len) { + uint8_t *p = (uint8_t *)(b + 1) - 1; + do { + DO_CRC(*++p); /* use pre increment for speed */ + } while (--len); + } + + return le32_to_cpu(crc); +} +#undef DO_CRC + +uint32_t ZEXPORT crc32 (uint32_t crc, const uchar *p, uint len) +{ + return crc32_no_comp(crc ^ 0xffffffffL, p, len) ^ 0xffffffffL; +} + diff --git a/linux-bsp/asm-study/myboot/include/asm/errno.h b/linux-bsp/asm-study/myboot/include/asm/errno.h new file mode 100644 index 0000000..f9cc47b --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/asm/errno.h @@ -0,0 +1,138 @@ +#ifndef _ARM_ERRNO_H +#define _ARM_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ +#define EDEADLOCK 58 /* File locking deadlock error */ +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + +/* Should never be seen by user programs */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 /* restart if no handler.. */ +#define ENOIOCTLCMD 515 /* No ioctl command */ + +#define _LAST_ERRNO 515 + +#endif diff --git a/linux-bsp/asm-study/myboot/include/asm/hardware.h b/linux-bsp/asm-study/myboot/include/asm/hardware.h new file mode 100644 index 0000000..a6e20ad --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/asm/hardware.h @@ -0,0 +1,43 @@ +#ifndef _ARCH_HARDWARE_H_ +#define _ARCH_HARDWARE_H_ + +#include <asm/sizes.h> + +#ifndef __ASSEMBLY__ +#define UData(Data) ((unsigned long) (Data)) + +#define __REG(x) (*(vu_long *)(x)) +#define __REGl(x) (*(vu_long *)(x)) +#define __REGi(x) (*(vu_int *)(x)) +#define __REGw(x) (*(vu_short *)(x)) +#define __REGb(x) (*(vu_char *)(x)) +#define __REG2(x,y) (*(vu_long *)((x) + (y))) +#else +#define UData(Data) (Data) + +#define __REG(x) (x) +#define __REGl(x) (x) +#define __REGi(x) (x) +#define __REGw(x) (x) +#define __REGb(x) (x) +#define __REG2(x,y) ((x) + (y)) +#endif + +#define Fld(Size, Shft) (((Size) << 16) + (Shft)) + +#define FSize(Field) ((Field) >> 16) +#define FShft(Field) ((Field) & 0x0000FFFF) +#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field)) +#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1) +#define F1stBit(Field) (UData (1) << FShft (Field)) + +#define FClrBit(Data, Bit) (Data = (Data & ~(Bit))) +#define FClrFld(Data, Field) (Data = (Data & ~FMsk(Field))) + +#define FInsrt(Value, Field) \ + (UData (Value) << FShft (Field)) + +#define FExtr(Data, Field) \ + ((UData (Data) >> FShft (Field)) & FAlnMsk (Field)) + +#endif /* _ARCH_HARDWARE_H_ */ diff --git a/linux-bsp/asm-study/myboot/include/asm/io.h b/linux-bsp/asm-study/myboot/include/asm/io.h new file mode 100644 index 0000000..8e5f5fd --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/asm/io.h @@ -0,0 +1,330 @@ +/* + * linux/include/asm-arm/io.h + * + * Copyright (C) 1996-2000 Russell King + * + * 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. + * + * Modifications: + * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both + * constant addresses and variable addresses. + * 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture + * specific IO header files. + * 27-Mar-1999 PJB Second parameter of memcpy_toio is const.. + * 04-Apr-1999 PJB Added check_signature. + * 12-Dec-1999 RMK More cleanups + * 18-Jun-2000 RMK Removed virt_to_* and friends definitions + */ +#ifndef __ASM_ARM_IO_H +#define __ASM_ARM_IO_H + +#ifdef __KERNEL__ + +#include <linux/types.h> + +static inline void sync(void) +{ +} + +/* + * Given a physical address and a length, return a virtual address + * that can be used to access the memory range with the caching + * properties specified by "flags". + */ +#define MAP_NOCACHE (0) +#define MAP_WRCOMBINE (0) +#define MAP_WRBACK (0) +#define MAP_WRTHROUGH (0) + +static inline void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) +{ + return (void *)paddr; +} + +/* + * Take down a mapping set up by map_physmem(). + */ +static inline void unmap_physmem(void *vaddr, unsigned long flags) +{ + +} + +/* + * Generic virtual read/write. Note that we don't support half-word + * read/writes. We define __arch_*[bl] here, and leave __arch_*w + * to the architecture specific code. + */ +#define __arch_getb(a) (*(volatile unsigned char *)(a)) +#define __arch_getw(a) (*(volatile unsigned short *)(a)) +#define __arch_getl(a) (*(volatile unsigned int *)(a)) + +#define __arch_putb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __arch_putw(v,a) (*(volatile unsigned short *)(a) = (v)) +#define __arch_putl(v,a) (*(volatile unsigned int *)(a) = (v)) + +extern void __raw_writesb(unsigned int addr, const void *data, int bytelen); +extern void __raw_writesw(unsigned int addr, const void *data, int wordlen); +extern void __raw_writesl(unsigned int addr, const void *data, int longlen); + +extern void __raw_readsb(unsigned int addr, void *data, int bytelen); +extern void __raw_readsw(unsigned int addr, void *data, int wordlen); +extern void __raw_readsl(unsigned int addr, void *data, int longlen); + +#define __raw_writeb(v,a) __arch_putb(v,a) +#define __raw_writew(v,a) __arch_putw(v,a) +#define __raw_writel(v,a) __arch_putl(v,a) + +#define __raw_readb(a) __arch_getb(a) +#define __raw_readw(a) __arch_getw(a) +#define __raw_readl(a) __arch_getl(a) + +#define writeb(v,a) __arch_putb(v,a) +#define writew(v,a) __arch_putw(v,a) +#define writel(v,a) __arch_putl(v,a) + +#define readb(a) __arch_getb(a) +#define readw(a) __arch_getw(a) +#define readl(a) __arch_getl(a) + +/* + * The compiler seems to be incapable of optimising constants + * properly. Spell it out to the compiler in some cases. + * These are only valid for small values of "off" (< 1<<12) + */ +#define __raw_base_writeb(val,base,off) __arch_base_putb(val,base,off) +#define __raw_base_writew(val,base,off) __arch_base_putw(val,base,off) +#define __raw_base_writel(val,base,off) __arch_base_putl(val,base,off) + +#define __raw_base_readb(base,off) __arch_base_getb(base,off) +#define __raw_base_readw(base,off) __arch_base_getw(base,off) +#define __raw_base_readl(base,off) __arch_base_getl(base,off) + +/* + * Now, pick up the machine-defined IO definitions + */ +#if 0 /* XXX###XXX */ +#include <asm/arch/io.h> +#endif /* XXX###XXX */ + +/* + * IO port access primitives + * ------------------------- + * + * The ARM doesn't have special IO access instructions; all IO is memory + * mapped. Note that these are defined to perform little endian accesses + * only. Their primary purpose is to access PCI and ISA peripherals. + * + * Note that for a big endian machine, this implies that the following + * big endian mode connectivity is in place, as described by numerous + * ARM documents: + * + * PCI: D0-D7 D8-D15 D16-D23 D24-D31 + * ARM: D24-D31 D16-D23 D8-D15 D0-D7 + * + * The machine specific io.h include defines __io to translate an "IO" + * address to a memory address. + * + * Note that we prevent GCC re-ordering or caching values in expressions + * by introducing sequence points into the in*() definitions. Note that + * __raw_* do not guarantee this behaviour. + * + * The {in,out}[bwl] macros are for emulating x86-style PCI/ISA IO space. + */ +#ifdef __io +#define outb(v,p) __raw_writeb(v,__io(p)) +#define outw(v,p) __raw_writew(cpu_to_le16(v),__io(p)) +#define outl(v,p) __raw_writel(cpu_to_le32(v),__io(p)) + +#define inb(p) ({ unsigned int __v = __raw_readb(__io(p)); __v; }) +#define inw(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(__io(p))); __v; }) +#define inl(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(__io(p))); __v; }) + +#define outsb(p,d,l) __raw_writesb(__io(p),d,l) +#define outsw(p,d,l) __raw_writesw(__io(p),d,l) +#define outsl(p,d,l) __raw_writesl(__io(p),d,l) + +#define insb(p,d,l) __raw_readsb(__io(p),d,l) +#define insw(p,d,l) __raw_readsw(__io(p),d,l) +#define insl(p,d,l) __raw_readsl(__io(p),d,l) +#endif + +#define outb_p(val,port) outb((val),(port)) +#define outw_p(val,port) outw((val),(port)) +#define outl_p(val,port) outl((val),(port)) +#define inb_p(port) inb((port)) +#define inw_p(port) inw((port)) +#define inl_p(port) inl((port)) + +#define outsb_p(port,from,len) outsb(port,from,len) +#define outsw_p(port,from,len) outsw(port,from,len) +#define outsl_p(port,from,len) outsl(port,from,len) +#define insb_p(port,to,len) insb(port,to,len) +#define insw_p(port,to,len) insw(port,to,len) +#define insl_p(port,to,len) insl(port,to,len) + +/* + * ioremap and friends. + * + * ioremap takes a PCI memory address, as specified in + * linux/Documentation/IO-mapping.txt. If you want a + * physical address, use __ioremap instead. + */ +extern void *__ioremap(unsigned long offset, size_t size, unsigned long flags); +extern void __iounmap(void *addr); + +/* + * Generic ioremap support. + * + * Define: + * iomem_valid_addr(off,size) + * iomem_to_phys(off) + */ +#ifdef iomem_valid_addr +#define __arch_ioremap(off,sz,nocache) \ + ({ \ + unsigned long _off = (off), _size = (sz); \ + void *_ret = (void *)0; \ + if (iomem_valid_addr(_off, _size)) \ + _ret = __ioremap(iomem_to_phys(_off),_size,0); \ + _ret; \ + }) + +#define __arch_iounmap __iounmap +#endif + +#define ioremap(off,sz) __arch_ioremap((off),(sz),0) +#define ioremap_nocache(off,sz) __arch_ioremap((off),(sz),1) +#define iounmap(_addr) __arch_iounmap(_addr) + +/* + * DMA-consistent mapping functions. These allocate/free a region of + * uncached, unwrite-buffered mapped memory space for use with DMA + * devices. This is the "generic" version. The PCI specific version + * is in pci.h + */ +extern void *consistent_alloc(int gfp, size_t size, dma_addr_t * handle); +extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); +extern void consistent_sync(void *vaddr, size_t size, int rw); + +/* + * String version of IO memory access ops: + */ +extern void _memcpy_fromio(void *, unsigned long, size_t); +extern void _memcpy_toio(unsigned long, const void *, size_t); +extern void _memset_io(unsigned long, int, size_t); + +extern void __readwrite_bug(const char *fn); + +/* + * If this architecture has PCI memory IO, then define the read/write + * macros. These should only be used with the cookie passed from + * ioremap. + */ +#ifdef __mem_pci + +#define readb(c) ({ unsigned int __v = __raw_readb(__mem_pci(c)); __v; }) +#define readw(c) ({ unsigned int __v = le16_to_cpu(__raw_readw(__mem_pci(c))); __v; }) +#define readl(c) ({ unsigned int __v = le32_to_cpu(__raw_readl(__mem_pci(c))); __v; }) + +#define writeb(v,c) __raw_writeb(v,__mem_pci(c)) +#define writew(v,c) __raw_writew(cpu_to_le16(v),__mem_pci(c)) +#define writel(v,c) __raw_writel(cpu_to_le32(v),__mem_pci(c)) + +#define memset_io(c,v,l) _memset_io(__mem_pci(c),(v),(l)) +#define memcpy_fromio(a,c,l) _memcpy_fromio((a),__mem_pci(c),(l)) +#define memcpy_toio(c,a,l) _memcpy_toio(__mem_pci(c),(a),(l)) + +#define eth_io_copy_and_sum(s,c,l,b) \ + eth_copy_and_sum((s),__mem_pci(c),(l),(b)) + +static inline int check_signature(unsigned long io_addr, const unsigned char *signature, int length) +{ + int retval = 0; + do + { + if (readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } + while (length); + retval = 1; + out: + return retval; +} + +#elif !defined(readb) + +#define readb(addr) (__readwrite_bug("readb"),0) +#define readw(addr) (__readwrite_bug("readw"),0) +#define readl(addr) (__readwrite_bug("readl"),0) +#define writeb(v,addr) __readwrite_bug("writeb") +#define writew(v,addr) __readwrite_bug("writew") +#define writel(v,addr) __readwrite_bug("writel") + +#define eth_io_copy_and_sum(a,b,c,d) __readwrite_bug("eth_io_copy_and_sum") + +#define check_signature(io,sig,len) (0) + +#endif /* __mem_pci */ + +/* + * If this architecture has ISA IO, then define the isa_read/isa_write + * macros. + */ +#ifdef __mem_isa + +#define isa_readb(addr) __raw_readb(__mem_isa(addr)) +#define isa_readw(addr) __raw_readw(__mem_isa(addr)) +#define isa_readl(addr) __raw_readl(__mem_isa(addr)) +#define isa_writeb(val,addr) __raw_writeb(val,__mem_isa(addr)) +#define isa_writew(val,addr) __raw_writew(val,__mem_isa(addr)) +#define isa_writel(val,addr) __raw_writel(val,__mem_isa(addr)) +#define isa_memset_io(a,b,c) _memset_io(__mem_isa(a),(b),(c)) +#define isa_memcpy_fromio(a,b,c) _memcpy_fromio((a),__mem_isa(b),(c)) +#define isa_memcpy_toio(a,b,c) _memcpy_toio(__mem_isa((a)),(b),(c)) + +#define isa_eth_io_copy_and_sum(a,b,c,d) \ + eth_copy_and_sum((a),__mem_isa(b),(c),(d)) + +static inline int +isa_check_signature(unsigned long io_addr, const unsigned char *signature, int length) +{ + int retval = 0; + do + { + if (isa_readb(io_addr) != *signature) + goto out; + io_addr++; + signature++; + length--; + } + while (length); + retval = 1; + out: + return retval; +} + +#else /* __mem_isa */ + +#define isa_readb(addr) (__readwrite_bug("isa_readb"),0) +#define isa_readw(addr) (__readwrite_bug("isa_readw"),0) +#define isa_readl(addr) (__readwrite_bug("isa_readl"),0) +#define isa_writeb(val,addr) __readwrite_bug("isa_writeb") +#define isa_writew(val,addr) __readwrite_bug("isa_writew") +#define isa_writel(val,addr) __readwrite_bug("isa_writel") +#define isa_memset_io(a,b,c) __readwrite_bug("isa_memset_io") +#define isa_memcpy_fromio(a,b,c) __readwrite_bug("isa_memcpy_fromio") +#define isa_memcpy_toio(a,b,c) __readwrite_bug("isa_memcpy_toio") + +#define isa_eth_io_copy_and_sum(a,b,c,d) \ + __readwrite_bug("isa_eth_io_copy_and_sum") + +#define isa_check_signature(io,sig,len) (0) + +#endif /* __mem_isa */ +#endif /* __KERNEL__ */ +#endif /* __ASM_ARM_IO_H */ diff --git a/linux-bsp/asm-study/myboot/include/asm/posix_types.h b/linux-bsp/asm-study/myboot/include/asm/posix_types.h new file mode 100644 index 0000000..1a6554a --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/asm/posix_types.h @@ -0,0 +1,80 @@ +/* + * linux/include/asm-arm/posix_types.h + * + * Copyright (C) 1996-1998 Russell King. + * + * 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. + * + * Changelog: + * 27-06-1996 RMK Created + */ +#ifndef __ARCH_ARM_POSIX_TYPES_H +#define __ARCH_ARM_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char *__kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct +{ +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31))) + +#undef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31))) + +#undef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp))) + +#endif + +#endif diff --git a/linux-bsp/asm-study/myboot/include/asm/sizes.h b/linux-bsp/asm-study/myboot/include/asm/sizes.h new file mode 100644 index 0000000..f8d92ca --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/asm/sizes.h @@ -0,0 +1,52 @@ +/* + * 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 + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/* Size defintions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_1K 0x00000400 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +#endif + +/* END */ diff --git a/linux-bsp/asm-study/myboot/include/asm/types.h b/linux-bsp/asm-study/myboot/include/asm/types.h new file mode 100644 index 0000000..27b55b2 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/asm/types.h @@ -0,0 +1,53 @@ +#ifndef __ASM_ARM_TYPES_H +#define __ASM_ARM_TYPES_H + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +typedef unsigned long phys_addr_t; +typedef unsigned long phys_size_t; + +#endif /* __KERNEL__ */ + +#endif diff --git a/linux-bsp/asm-study/myboot/include/bignum.h b/linux-bsp/asm-study/myboot/include/bignum.h new file mode 100644 index 0000000..3ffa5cb --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/bignum.h @@ -0,0 +1,380 @@ +/** + * \file bignum.h + */ +#ifndef _BIGNUM_H +#define _BIGNUM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define ERR_MPI_INVALID_CHARACTER 0x0002 +#define ERR_MPI_INVALID_PARAMETER 0x0004 +#define ERR_MPI_BUFFER_TOO_SMALL 0x0006 +#define ERR_MPI_NEGATIVE_VALUE 0x0008 +#define ERR_MPI_DIVISION_BY_ZERO 0x000A +#define ERR_MPI_NOT_INVERTIBLE 0x000C +#define ERR_MPI_IS_COMPOSITE 0x000E + +#define CHK(fc) if( ( ret = fc ) != 0 ) goto cleanup + +/* + * Define the base limb type + */ +#if defined(HAVE_INT16) /* 8086 */ +typedef unsigned int t_int; +typedef unsigned long t_dbl; +#else +typedef unsigned long t_int; +typedef unsigned long long t_dbl; +#endif + +#define ciL (int) sizeof(t_int) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + int n; /*!< total # of limbs */ +// t_int *p; /*!< pointer to limbs */ + unsigned long long *p; /*!< pointer to limbs */ +} +mpi; + +/** + * \brief Initialize one or more mpi + */ +void mpi_init( mpi *X, ... ); + +/** + * \brief Unallocate one or more mpi + */ +void mpi_free( mpi *X, ... ); + +/** + * \brief Enlarge X to the specified # of limbs + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_grow( mpi *X, int nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_copy( mpi *X, mpi *Y ); + +/** + * \brief Swap the contents of X and Y + */ +void mpi_swap( mpi *X, mpi *Y ); + +/** + * \brief Set value from integer + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_lset( mpi *X, int z ); + +/** + * \brief Set value from string + * + * \param X destination mpi + * \param s string to read the value from + * \param radix numeric base of "s" + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_INVALID_PARAMETER if the radix is invalid + * ERR_MPI_INVALID_CHARACTER if a non-digit is found + */ +int mpi_read( mpi *X, char *s, int radix ); + +/** + * \brief Print the value of X into fout + * + * \param name string printed before the value + * \param X mpi to be printed + * \param radix chosen numeric base + * \param fout output file stream + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_INVALID_PARAMETER if the radix is invalid + */ +int mpi_showf( char *name, mpi *X, int radix, FILE *fout ); + +/** + * \brief Print the value of X on the console + * + * \param name string printed before the value + * \param X mpi to be printed + * \param radix chosen numeric base + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_INVALID_PARAMETER if the radix is invalid + */ +int mpi_show( char *name, mpi *X, int radix ); + +/** + * \brief Import an unsigned value from binary data + * + * \param X destination mpi + * \param buf input buffer + * \param buflen size of buffer + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_import( mpi *X, unsigned char *buf, int buflen ); + +/** + * \brief Export an unsigned value into binary data + * + * \param X source mpi + * \param buf output buffer + * \param buflen size of buffer + * + * \return 0 if successful, + * ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + * + * \note Call this function with *buflen = 0 to obtain the + * required buffer size in *buflen. + */ +int mpi_export( mpi *X, unsigned char *buf, int *buflen ); + +/** + * \brief Return actual size in bits (without leading 0s) + */ +int mpi_size( mpi *X ); + +/** + * \brief Return number of least significant bits + */ +int mpi_lsb( mpi *X ); + +/** + * \brief Left-shift: X <<= count + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_shift_l( mpi *X, int count ); + +/** + * \brief Right-shift: X >>= count + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_shift_r( mpi *X, int count ); + +/** + * \brief Compare unsigned values + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mpi_cmp_abs( mpi *X, mpi *Y ); + +/** + * \brief Compare signed values + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mpi_cmp_mpi( mpi *X, mpi *Y ); + +/** + * \brief Compare signed values + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mpi_cmp_int( mpi *X, int z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_abs( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Unsigned substraction: X = |A| - |B| + * + * \return 0 if successful, + * ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mpi_sub_abs( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_mpi( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Signed substraction: X = A - B + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_sub_mpi( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_add_int( mpi *X, mpi *A, int b ); + +/** + * \brief Signed substraction: X = A - b + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_sub_int( mpi *X, mpi *A, int b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_mul_mpi( mpi *X, mpi *A, mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_mul_int( mpi *X, mpi *A, t_int b ); + +/** + * \brief Division by mpi: A = Q * B + R + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_mpi( mpi *Q, mpi *R, mpi *A, mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mpi_div_int( mpi *Q, mpi *R, mpi *A, int b ); + +/** + * \brief Modulo: R = A mod B + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if B == 0 + */ +int mpi_mod_mpi( mpi *R, mpi *A, mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_DIVISION_BY_ZERO if b == 0, + */ +int mpi_mod_int( t_int *r, mpi *A, int b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_INVALID_PARAMETER if N is negative or even + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mpi_exp_mod( mpi *X, mpi *A, mpi *E, mpi *N, mpi *_RR ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \return 0 if successful, + * 1 if memory allocation failed + */ +int mpi_gcd( mpi *G, mpi *A, mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \return 0 if successful, + * 1 if memory allocation failed, + * ERR_MPI_INVALID_PARAMETER if N is negative or nil + * ERR_MPI_NOT_INVERTIBLE if A has no inverse mod N + */ +int mpi_inv_mod( mpi *X, mpi *A, mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \return 0 if successful (probably prime), + * 1 if memory allocation failed, + * ERR_MPI_IS_COMPOSITE if X is not prime + */ +int mpi_is_prime( mpi *X ); + +/** + * \brief Prime number generation + * + * \param X destination mpi + * \param nbits required size of X in bits + * \param dh_flag set this to 1 if (X-1)/2 must also be prime + * (needed for Diffie-Hellman) + * \param rng_f points to the RNG function + * \param rng_d points to the RNG data + * + * \return 0 if successful (probably prime), + * 1 if memory allocation failed, + * ERR_MPI_INVALID_PARAMETER if nbits is < 3 + */ +int mpi_gen_prime( mpi *X, int nbits, int dh_flag, + int (*rng_f)(void *), void *rng_d ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mpi_self_test( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/linux-bsp/asm-study/myboot/include/bn_asm.h b/linux-bsp/asm-study/myboot/include/bn_asm.h new file mode 100644 index 0000000..10484e0 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/bn_asm.h @@ -0,0 +1,549 @@ +/** + * \file bn_asm.h + * + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + */ +#ifndef _BN_ASM_H +#define _BN_ASM_H + +#if defined(__GNUC__) +#if defined(__i386__) + +#define MULADDC_INIT \ + asm( "movl %0, %%esi " :: "m" (s)); \ + asm( "movl %0, %%edi " :: "m" (d)); \ + asm( "movl %0, %%ecx " :: "m" (c)); \ + asm( "movl %0, %%ebx " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "lodsl " ); \ + asm( "mull %ebx " ); \ + asm( "addl %ecx, %eax " ); \ + asm( "adcl $0, %edx " ); \ + asm( "addl (%edi), %eax " ); \ + asm( "adcl $0, %edx " ); \ + asm( "movl %edx, %ecx " ); \ + asm( "stosl " ); + +#define MULADDC_STOP \ + asm( "movl %%ecx, %0 " : "=m" (c)); \ + asm( "movl %%edi, %0 " : "=m" (d)); \ + asm( "movl %%esi, %0 " : "=m" (s) :: \ + "eax", "ecx", "edx", "ebx", "esi", "edi" ); + +#if defined(HAVE_SSE2) + +#define MULADDC_HUIT \ + asm( "movd %ecx, %mm1 " ); \ + asm( "movd %ebx, %mm0 " ); \ + asm( "movd (%edi), %mm3 " ); \ + asm( "paddq %mm3, %mm1 " ); \ + asm( "movd (%esi), %mm2 " ); \ + asm( "pmuludq %mm0, %mm2 " ); \ + asm( "movd 4(%esi), %mm4 " ); \ + asm( "pmuludq %mm0, %mm4 " ); \ + asm( "movd 8(%esi), %mm6 " ); \ + asm( "pmuludq %mm0, %mm6 " ); \ + asm( "movd 12(%esi), %mm7 " ); \ + asm( "pmuludq %mm0, %mm7 " ); \ + asm( "paddq %mm2, %mm1 " ); \ + asm( "movd 4(%edi), %mm3 " ); \ + asm( "paddq %mm4, %mm3 " ); \ + asm( "movd 8(%edi), %mm5 " ); \ + asm( "paddq %mm6, %mm5 " ); \ + asm( "movd 12(%edi), %mm4 " ); \ + asm( "paddq %mm4, %mm7 " ); \ + asm( "movd %mm1, (%edi) " ); \ + asm( "movd 16(%esi), %mm2 " ); \ + asm( "pmuludq %mm0, %mm2 " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "movd 20(%esi), %mm4 " ); \ + asm( "pmuludq %mm0, %mm4 " ); \ + asm( "paddq %mm3, %mm1 " ); \ + asm( "movd 24(%esi), %mm6 " ); \ + asm( "pmuludq %mm0, %mm6 " ); \ + asm( "movd %mm1, 4(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "movd 28(%esi), %mm3 " ); \ + asm( "pmuludq %mm0, %mm3 " ); \ + asm( "paddq %mm5, %mm1 " ); \ + asm( "movd 16(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm2 " ); \ + asm( "movd %mm1, 8(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm7, %mm1 " ); \ + asm( "movd 20(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm4 " ); \ + asm( "movd %mm1, 12(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm2, %mm1 " ); \ + asm( "movd 24(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm6 " ); \ + asm( "movd %mm1, 16(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm4, %mm1 " ); \ + asm( "movd 28(%edi), %mm5 " ); \ + asm( "paddq %mm5, %mm3 " ); \ + asm( "movd %mm1, 20(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm6, %mm1 " ); \ + asm( "movd %mm1, 24(%edi) " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "paddq %mm3, %mm1 " ); \ + asm( "movd %mm1, 28(%edi) " ); \ + asm( "addl $32, %edi " ); \ + asm( "addl $32, %esi " ); \ + asm( "psrlq $32, %mm1 " ); \ + asm( "movd %mm1, %ecx " ); + +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( "movq %0, %%rsi " :: "m" (s)); \ + asm( "movq %0, %%rdi " :: "m" (d)); \ + asm( "movq %0, %%rcx " :: "m" (c)); \ + asm( "movq %0, %%rbx " :: "m" (b)); \ + asm( "xorq %r8, %r8 " ); + +#define MULADDC_CORE \ + asm( "movq (%rsi),%rax " ); \ + asm( "mulq %rbx " ); \ + asm( "addq $8, %rsi " ); \ + asm( "addq %rcx, %rax " ); \ + asm( "movq %r8, %rcx " ); \ + asm( "adcq $0, %rdx " ); \ + asm( "nop " ); \ + asm( "addq %rax, (%rdi) " ); \ + asm( "adcq %rdx, %rcx " ); \ + asm( "addq $8, %rdi " ); + +#define MULADDC_STOP \ + asm( "movq %%rcx, %0 " : "=m" (c)); \ + asm( "movq %%rdi, %0 " : "=m" (d)); \ + asm( "movq %%rsi, %0 " : "=m" (s) :: \ + "rax", "rcx", "rdx", "rbx", "rsi", "rdi", "r8" ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( "movl %0, %%a2 " :: "m" (s)); \ + asm( "movl %0, %%a3 " :: "m" (d)); \ + asm( "movl %0, %%d3 " :: "m" (c)); \ + asm( "movl %0, %%d2 " :: "m" (b)); \ + asm( "moveq #0, %d0 " ); + +#define MULADDC_CORE \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "moveq #0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d4, %d3 " ); + +#define MULADDC_STOP \ + asm( "movl %%d3, %0 " : "=m" (c)); \ + asm( "movl %%a3, %0 " : "=m" (d)); \ + asm( "movl %%a2, %0 " : "=m" (s) :: \ + "d0", "d1", "d2", "d3", "d4", "a2", "a3" ); + +#define MULADDC_HUIT \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d4:%d1 " ); \ + asm( "addxl %d3, %d1 " ); \ + asm( "addxl %d0, %d4 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "movel %a2@+, %d1 " ); \ + asm( "mulul %d2, %d3:%d1 " ); \ + asm( "addxl %d4, %d1 " ); \ + asm( "addxl %d0, %d3 " ); \ + asm( "addl %d1, %a3@+ " ); \ + asm( "addxl %d0, %d3 " ); + +#endif /* MC68020 */ + +#if defined(__powerpc__) || defined(__ppc__) +#if defined(__powerpc64__) || defined(__ppc64__) + +#define MULADDC_INIT \ + asm( "ld %%r3, %0 " :: "m" (s)); \ + asm( "ld %%r4, %0 " :: "m" (d)); \ + asm( "ld %%r5, %0 " :: "m" (c)); \ + asm( "ld %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -8 " ); \ + asm( "addi %r4, %r4, -8 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "ldu %r7, 8(%r3) " ); \ + asm( "mulld %r8, %r7, %r6 " ); \ + asm( "mulhdu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "ld %r7, 8(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stdu %r8, 8(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 8 " ); \ + asm( "addi %r3, %r3, 8 " ); \ + asm( "std %%r5, %0 " : "=m" (c)); \ + asm( "std %%r4, %0 " : "=m" (d)); \ + asm( "std %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#else + +#define MULADDC_INIT \ + asm( "lwz %%r3, %0 " :: "m" (s)); \ + asm( "lwz %%r4, %0 " :: "m" (d)); \ + asm( "lwz %%r5, %0 " :: "m" (c)); \ + asm( "lwz %%r6, %0 " :: "m" (b)); \ + asm( "addi %r3, %r3, -4 " ); \ + asm( "addi %r4, %r4, -4 " ); \ + asm( "addic %r5, %r5, 0 " ); + +#define MULADDC_CORE \ + asm( "lwzu %r7, 4(%r3) " ); \ + asm( "mullw %r8, %r7, %r6 " ); \ + asm( "mulhwu %r9, %r7, %r6 " ); \ + asm( "adde %r8, %r8, %r5 " ); \ + asm( "lwz %r7, 4(%r4) " ); \ + asm( "addze %r5, %r9 " ); \ + asm( "addc %r8, %r8, %r7 " ); \ + asm( "stwu %r8, 4(%r4) " ); + +#define MULADDC_STOP \ + asm( "addze %r5, %r5 " ); \ + asm( "addi %r4, %r4, 4 " ); \ + asm( "addi %r3, %r3, 4 " ); \ + asm( "stw %%r5, %0 " : "=m" (c)); \ + asm( "stw %%r4, %0 " : "=m" (d)); \ + asm( "stw %%r3, %0 " : "=m" (s) :: \ + "r3", "r4", "r5", "r6", "r7", "r8", "r9" ); + +#endif /* PowerPC 32-bit */ +#endif /* PowerPC 64-bit */ + +#if defined(__sparc__) + +#define MULADDC_INIT \ + asm( "ld %0, %%o0 " :: "m" (s)); \ + asm( "ld %0, %%o1 " :: "m" (d)); \ + asm( "ld %0, %%o2 " :: "m" (c)); \ + asm( "ld %0, %%o3 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ld [%o0], %o4 " ); \ + asm( "inc 4, %o0 " ); \ + asm( "ld [%o1], %o5 " ); \ + asm( "umul %o3, %o4, %o4 " ); \ + asm( "addcc %o4, %o2, %o4 " ); \ + asm( "rd %y, %g1 " ); \ + asm( "addx %g1, 0, %g1 " ); \ + asm( "addcc %o4, %o5, %o4 " ); \ + asm( "st %o4, [%o1] " ); \ + asm( "addx %g1, 0, %o2 " ); \ + asm( "inc 4, %o1 " ); + +#define MULADDC_STOP \ + asm( "st %%o2, %0 " : "=m" (c)); \ + asm( "st %%o1, %0 " : "=m" (d)); \ + asm( "st %%o0, %0 " : "=m" (s) :: \ + "g1", "o0", "o1", "o2", "o3", "o4", "o5" ); + +#endif /* SPARC8 */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( "ld.a %%a2, %0 " :: "m" (s)); \ + asm( "ld.a %%a3, %0 " :: "m" (d)); \ + asm( "ld.w %%d4, %0 " :: "m" (c)); \ + asm( "ld.w %%d1, %0 " :: "m" (b)); \ + asm( "xor %d5, %d5 " ); + +#define MULADDC_CORE \ + asm( "ld.w %d0, [%a2+] " ); \ + asm( "madd.u %e2, %e4, %d0, %d1 " ); \ + asm( "ld.w %d0, [%a3] " ); \ + asm( "addx %d2, %d2, %d0 " ); \ + asm( "addc %d3, %d3, 0 " ); \ + asm( "mov %d4, %d3 " ); \ + asm( "st.w [%a3+], %d2 " ); + +#define MULADDC_STOP \ + asm( "st.w %0, %%d4 " : "=m" (c)); \ + asm( "st.a %0, %%a3 " : "=m" (d)); \ + asm( "st.a %0, %%a2 " : "=m" (s) :: \ + "d0", "d1", "e2", "d4", "a2", "a3" ); + +#endif /* TriCore */ + +#if defined(__arm__) + +#define MULADDC_INIT \ + asm( "ldr r0, %0 " :: "m" (s)); \ + asm( "ldr r1, %0 " :: "m" (d)); \ + asm( "ldr r2, %0 " :: "m" (c)); \ + asm( "ldr r3, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldr r4, [r0], #4 " ); \ + asm( "mov r5, #0 " ); \ + asm( "ldr r6, [r1] " ); \ + asm( "umlal r2, r5, r3, r4 " ); \ + asm( "adds r7, r6, r2 " ); \ + asm( "adc r2, r5, #0 " ); \ + asm( "str r7, [r1], #4 " ); + +#define MULADDC_STOP \ + asm( "str r2, %0 " : "=m" (c)); \ + asm( "str r1, %0 " : "=m" (d)); \ + asm( "str r0, %0 " : "=m" (s) :: \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7" ); + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( "ldq $1, %0 " :: "m" (s)); \ + asm( "ldq $2, %0 " :: "m" (d)); \ + asm( "ldq $3, %0 " :: "m" (c)); \ + asm( "ldq $4, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "ldq $6, 0($1) " ); \ + asm( "addq $1, 8, $1 " ); \ + asm( "mulq $6, $4, $7 " ); \ + asm( "umulh $6, $4, $6 " ); \ + asm( "addq $7, $3, $7 " ); \ + asm( "cmpult $7, $3, $3 " ); \ + asm( "ldq $5, 0($2) " ); \ + asm( "addq $7, $5, $7 " ); \ + asm( "cmpult $7, $5, $5 " ); \ + asm( "stq $7, 0($2) " ); \ + asm( "addq $2, 8, $2 " ); \ + asm( "addq $6, $3, $3 " ); \ + asm( "addq $5, $3, $3 " ); + +#define MULADDC_STOP \ + asm( "stq $3, %0 " : "=m" (c)); \ + asm( "stq $2, %0 " : "=m" (d)); \ + asm( "stq $1, %0 " : "=m" (s) :: \ + "$1", "$2", "$3", "$4", "$5", "$6", "$7" ); + +#endif /* Alpha */ + +#if defined(__mips__) + +#define MULADDC_INIT \ + asm( "lw $10, %0 " :: "m" (s)); \ + asm( "lw $11, %0 " :: "m" (d)); \ + asm( "lw $12, %0 " :: "m" (c)); \ + asm( "lw $13, %0 " :: "m" (b)); + +#define MULADDC_CORE \ + asm( "lw $14, 0($10) " ); \ + asm( "multu $13, $14 " ); \ + asm( "addi $10, $10, 4 " ); \ + asm( "mflo $14 " ); \ + asm( "mfhi $9 " ); \ + asm( "addu $14, $12, $14 " ); \ + asm( "lw $15, 0($11) " ); \ + asm( "sltu $12, $14, $12 " ); \ + asm( "addu $15, $14, $15 " ); \ + asm( "sltu $14, $15, $14 " ); \ + asm( "addu $12, $12, $9 " ); \ + asm( "sw $15, 0($11) " ); \ + asm( "addu $12, $12, $14 " ); \ + asm( "addi $11, $11, 4 " ); + +#define MULADDC_STOP \ + asm( "sw $12, %0 " : "=m" (c)); \ + asm( "sw $11, %0 " : "=m" (d)); \ + asm( "sw $10, %0 " : "=m" (s) :: \ + "$9", "$10", "$11", "$12", "$13", "$14", "$15" ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#if defined HAVE_SSE2 + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#endif /* SSE2 */ +#endif /* MSVC */ + +#if !defined(MULADDC_CORE) +#if defined(HAVE_LONGLONG) + +#define MULADDC_INIT \ +{ \ + t_dbl r; \ + t_int r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (t_dbl) b; \ + r0 = r; \ + r1 = r >> biL; \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + t_int s0, s1, b0, b1; \ + t_int r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_asm.h */ diff --git a/linux-bsp/asm-study/myboot/include/common.h b/linux-bsp/asm-study/myboot/include/common.h new file mode 100644 index 0000000..13dd894 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/common.h @@ -0,0 +1,52 @@ +/******************************************************************************************** + * File: common.h + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: A busy head file + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#ifndef __COMMON_H +#define __COMMON_H + +#include <stdarg.h> +#include <config.h> +#include <asm/types.h> +#include <asm/io.h> +#include <linux/types.h> + +#define DEBUG +#ifdef DEBUG +#define dbg_print(format,args...) printf(format, ##args) +#else +#define dbg_print(format,args...) do{} while(0); +#endif + +typedef unsigned char uchar; +typedef volatile unsigned long vu_long; +typedef volatile unsigned short vu_short; +typedef volatile unsigned char vu_char; +typedef volatile unsigned int vu_int; + +/*Define in board.c*/ +inline void delay(unsigned long loops); +void init_led_beep(void); +void turn_led_on(int led); +void turn_led_off(int led); +void beep(int count); + +void serial_init(void); +void serial_send_byte(char c); +int serial_is_recv_enable(void); +int serial_recv_byte(void); +void serial_puts(const char *s); +long xmodem_recv(char *buf); + +/*Define in printf.c*/ +void * memset(void * s,int c,size_t count); +void printf(const char *fmt, ...); +int sprintf(char *buf, const char *fmt, ...); + + +#endif diff --git a/linux-bsp/asm-study/myboot/include/config.h b/linux-bsp/asm-study/myboot/include/config.h new file mode 100644 index 0000000..297b4df --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/config.h @@ -0,0 +1,36 @@ +/******************************************************************************************** + * File: start.S - Startup Code for ARM920 CPU-core + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: Configure file for bootstrap, just like u-boot-1.3.4/include/config/s3c2440.h + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#ifdef BOARD_SMDK2440 +#include <s3c2440.h> +#define CONFIG_S3C2440 +#endif + +#define MDIV_405 0x7f << 12 +#define PSDIV_405 0x21 + +#define CONFIG_LED_DEBUG 1 + +#define CONFIG_SYS_MALLOC_LEN (1024*1024) +#define CONFIG_SYS_GBL_DATA_SIZE 128 +#define CONFIG_STACKSIZE 0x40000 + +#define CFG_PBSIZE 384 /* Print Buffer Size */ + +#define CFG_MAX_NAND_DEVICE 1 +#define NAND_MAX_CHIPS 1 +#define CFG_NAND_BASE 0x4E000000 + +#define BOOTLOADER_ENV_ADDR 0x20000 /*Bootloader enviroment start address*/ +#define LAUNCHER_NAND_ADDR 0x40000 /*Laucher save in Nandflash address*/ + +#endif diff --git a/linux-bsp/asm-study/myboot/include/linux/bitops.h b/linux-bsp/asm-study/myboot/include/linux/bitops.h new file mode 100644 index 0000000..19a34db --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/bitops.h @@ -0,0 +1,75 @@ +#ifndef _LINUX_BITOPS_H +#define _LINUX_BITOPS_H + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +static inline int generic_ffs(int x) +{ + int r = 1; + + if (!x) + return 0; + if (!(x & 0xffff)) + { + x >>= 16; + r += 16; + } + if (!(x & 0xff)) + { + x >>= 8; + r += 8; + } + if (!(x & 0xf)) + { + x >>= 4; + r += 4; + } + if (!(x & 3)) + { + x >>= 2; + r += 2; + } + if (!(x & 1)) + { + x >>= 1; + r += 1; + } + return r; +} + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +static inline unsigned int generic_hweight32(unsigned int w) +{ + unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555); + res = (res & 0x33333333) + ((res >> 2) & 0x33333333); + res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F); + res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF); + return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF); +} + +static inline unsigned int generic_hweight16(unsigned int w) +{ + unsigned int res = (w & 0x5555) + ((w >> 1) & 0x5555); + res = (res & 0x3333) + ((res >> 2) & 0x3333); + res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F); + return (res & 0x00FF) + ((res >> 8) & 0x00FF); +} + +static inline unsigned int generic_hweight8(unsigned int w) +{ + unsigned int res = (w & 0x55) + ((w >> 1) & 0x55); + res = (res & 0x33) + ((res >> 2) & 0x33); + return (res & 0x0F) + ((res >> 4) & 0x0F); +} + +//#include <asm/bitops.h> + +#endif diff --git a/linux-bsp/asm-study/myboot/include/linux/config.h b/linux-bsp/asm-study/myboot/include/linux/config.h new file mode 100644 index 0000000..a0194cb --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/config.h @@ -0,0 +1,6 @@ +#ifndef _LINUX_CONFIG_H +#define _LINUX_CONFIG_H + +/* #include <linux/autoconf.h> */ + +#endif diff --git a/linux-bsp/asm-study/myboot/include/linux/ctype.h b/linux-bsp/asm-study/myboot/include/linux/ctype.h new file mode 100644 index 0000000..9d7eca2 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/ctype.h @@ -0,0 +1,54 @@ +#ifndef _LINUX_CTYPE_H +#define _LINUX_CTYPE_H + +/* + * NOTE! This ctype does not handle EOF like the standard C + * library is required to. + */ + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern unsigned char _ctype[]; + +#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) + +#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) +#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) +#define iscntrl(c) ((__ismask(c)&(_C)) != 0) +#define isdigit(c) ((__ismask(c)&(_D)) != 0) +#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) +#define islower(c) ((__ismask(c)&(_L)) != 0) +#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) +#define ispunct(c) ((__ismask(c)&(_P)) != 0) +#define isspace(c) ((__ismask(c)&(_S)) != 0) +#define isupper(c) ((__ismask(c)&(_U)) != 0) +#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) + +#define isascii(c) (((unsigned char)(c))<=0x7f) +#define toascii(c) (((unsigned char)(c))&0x7f) + +static inline unsigned char __tolower(unsigned char c) +{ + if (isupper(c)) + c -= 'A' - 'a'; + return c; +} + +static inline unsigned char __toupper(unsigned char c) +{ + if (islower(c)) + c -= 'a' - 'A'; + return c; +} + +#define tolower(c) __tolower(c) +#define toupper(c) __toupper(c) + +#endif diff --git a/linux-bsp/asm-study/myboot/include/linux/posix_types.h b/linux-bsp/asm-study/myboot/include/linux/posix_types.h new file mode 100644 index 0000000..8a13ff2 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/posix_types.h @@ -0,0 +1,49 @@ +#ifndef _LINUX_POSIX_TYPES_H +#define _LINUX_POSIX_TYPES_H + +#include <linux/stddef.h> + +/* + * This allows for 1024 file descriptors: if NR_OPEN is ever grown + * beyond that you'll have to change this too. But 1024 fd's seem to be + * enough even for such "real" unices like OSF/1, so hopefully this is + * one limit that doesn't have to be changed [again]. + * + * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in + * <sys/time.h> (and thus <linux/time.h>) - but this is a more logical + * place for them. Solved by having dummy defines in <sys/time.h>. + */ + +/* + * Those macros may have been defined in <gnu/types.h>. But we always + * use the ones here. + */ +#undef __NFDBITS +#define __NFDBITS (8 * sizeof(unsigned long)) + +#undef __FD_SETSIZE +#define __FD_SETSIZE 1024 + +#undef __FDSET_LONGS +#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS) + +#undef __FDELT +#define __FDELT(d) ((d) / __NFDBITS) + +#undef __FDMASK +#define __FDMASK(d) (1UL << ((d) % __NFDBITS)) + +typedef struct +{ + unsigned long fds_bits[__FDSET_LONGS]; +} __kernel_fd_set; + +/* Type of a signal handler. */ +typedef void (*__kernel_sighandler_t) (int); + +/* Type of a SYSV IPC key. */ +typedef int __kernel_key_t; + +#include <asm/posix_types.h> + +#endif /* _LINUX_POSIX_TYPES_H */ diff --git a/linux-bsp/asm-study/myboot/include/linux/stddef.h b/linux-bsp/asm-study/myboot/include/linux/stddef.h new file mode 100644 index 0000000..81e34c2 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/stddef.h @@ -0,0 +1,18 @@ +#ifndef _LINUX_STDDEF_H +#define _LINUX_STDDEF_H + +#undef NULL +#if defined(__cplusplus) +#define NULL 0 +#else +#define NULL ((void *)0) +#endif + +#ifndef _SIZE_T +#include <linux/types.h> +#endif + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif diff --git a/linux-bsp/asm-study/myboot/include/linux/string.h b/linux-bsp/asm-study/myboot/include/linux/string.h new file mode 100644 index 0000000..33d4d8d --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/string.h @@ -0,0 +1,89 @@ +#ifndef _LINUX_STRING_H_ +#define _LINUX_STRING_H_ + +#include <linux/types.h> /* for size_t */ +#include <linux/stddef.h> /* for NULL */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + extern char *___strtok; + extern char *strpbrk(const char *, const char *); + extern char *strtok(char *, const char *); + extern char *strsep(char **, const char *); + extern __kernel_size_t strspn(const char *, const char *); + +/* + * Include machine specific inline routines + */ +#include <asm/string.h> + +#ifndef __HAVE_ARCH_STRCPY + extern char *strcpy(char *, const char *); +#endif +#ifndef __HAVE_ARCH_STRNCPY + extern char *strncpy(char *, const char *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRCAT + extern char *strcat(char *, const char *); +#endif +#ifndef __HAVE_ARCH_STRNCAT + extern char *strncat(char *, const char *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRCMP + extern int strcmp(const char *, const char *); +#endif +#ifndef __HAVE_ARCH_STRNCMP + extern int strncmp(const char *, const char *, __kernel_size_t); +#endif +#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ + extern int strnicmp(const char *, const char *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRCHR + extern char *strchr(const char *, int); +#endif +#ifndef __HAVE_ARCH_STRRCHR + extern char *strrchr(const char *, int); +#endif +#ifndef __HAVE_ARCH_STRSTR + extern char *strstr(const char *, const char *); +#endif +#ifndef __HAVE_ARCH_STRLEN + extern __kernel_size_t strlen(const char *); +#endif +#ifndef __HAVE_ARCH_STRNLEN + extern __kernel_size_t strnlen(const char *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRDUP + extern char *strdup(const char *); +#endif +#ifndef __HAVE_ARCH_STRSWAB + extern char *strswab(const char *); +#endif + +#ifndef __HAVE_ARCH_MEMSET + extern void *memset(void *, int, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMCPY + extern void *memcpy(void *, const void *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMMOVE + extern void *memmove(void *, const void *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMSCAN + extern void *memscan(void *, int, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMCMP + extern int memcmp(const void *, const void *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMCHR + extern void *memchr(const void *, int, __kernel_size_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _LINUX_STRING_H_ */ diff --git a/linux-bsp/asm-study/myboot/include/linux/time.h b/linux-bsp/asm-study/myboot/include/linux/time.h new file mode 100644 index 0000000..c00a461 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/time.h @@ -0,0 +1,149 @@ +#ifndef _LINUX_TIME_H +#define _LINUX_TIME_H + +#include <linux/types.h> + +#define _DEFUN(a,b,c) a(c) +#define _CONST const +#define _AND , + +#define _REENT_ONLY + +#define SECSPERMIN 60L +#define MINSPERHOUR 60L +#define HOURSPERDAY 24L +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define SECSPERDAY (SECSPERHOUR * HOURSPERDAY) +#define DAYSPERWEEK 7 +#define MONSPERYEAR 12 + +#define YEAR_BASE 1900 +#define EPOCH_YEAR 1970 +#define EPOCH_WDAY 4 + +#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) + +/* Used by other time functions. */ +struct tm +{ + int tm_sec; /* Seconds. [0-60] (1 leap second) */ + int tm_min; /* Minutes. [0-59] */ + int tm_hour; /* Hours. [0-23] */ + int tm_mday; /* Day. [1-31] */ + int tm_mon; /* Month. [0-11] */ + int tm_year; /* Year - 1900. */ + int tm_wday; /* Day of week. [0-6] */ + int tm_yday; /* Days in year.[0-365] */ + int tm_isdst; /* DST. [-1/0/1] */ + +# ifdef __USE_BSD + long int tm_gmtoff; /* Seconds east of UTC. */ + __const char *tm_zone; /* Timezone abbreviation. */ +# else + long int __tm_gmtoff; /* Seconds east of UTC. */ + __const char *__tm_zone; /* Timezone abbreviation. */ +# endif +}; + +static inline char *_DEFUN(asctime_r, (tim_p, result), _CONST struct tm *tim_p _AND char *result) +{ + static _CONST char day_name[7][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static _CONST char mon_name[12][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + sprintf(result, "%.3s %.3s %.2d %.2d:%.2d:%.2d %d\n", + day_name[tim_p->tm_wday], + mon_name[tim_p->tm_mon], + tim_p->tm_mday, tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec, 1900 + tim_p->tm_year); + return result; +} + +static inline struct tm *_DEFUN(localtime_r, (tim_p, res), + _CONST time_t * tim_p _AND struct tm *res) +{ + static _CONST int mon_lengths[2][MONSPERYEAR] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} + }; + + static _CONST int year_lengths[2] = { + 365, + 366 + }; + + long days, rem; + int y; + int yleap; + _CONST int *ip; + + days = ((long)*tim_p) / SECSPERDAY; + rem = ((long)*tim_p) % SECSPERDAY; + while (rem < 0) + { + rem += SECSPERDAY; + --days; + } + while (rem >= SECSPERDAY) + { + rem -= SECSPERDAY; + ++days; + } + + /* compute hour, min, and sec */ + res->tm_hour = (int)(rem / SECSPERHOUR); + rem %= SECSPERHOUR; + res->tm_min = (int)(rem / SECSPERMIN); + res->tm_sec = (int)(rem % SECSPERMIN); + + /* compute day of week */ + if ((res->tm_wday = ((EPOCH_WDAY + days) % DAYSPERWEEK)) < 0) + res->tm_wday += DAYSPERWEEK; + + /* compute year & day of year */ + y = EPOCH_YEAR; + if (days >= 0) + { + for (;;) + { + yleap = isleap(y); + if (days < year_lengths[yleap]) + break; + y++; + days -= year_lengths[yleap]; + } + } + else + { + do + { + --y; + yleap = isleap(y); + days += year_lengths[yleap]; + } + while (days < 0); + } + + res->tm_year = y - YEAR_BASE; + res->tm_yday = days; + ip = mon_lengths[yleap]; + for (res->tm_mon = 0; days >= ip[res->tm_mon]; ++res->tm_mon) + days -= ip[res->tm_mon]; + res->tm_mday = days + 1; + + /* set daylight saving time flag */ + res->tm_isdst = -1; + + return (res); +} + +static inline char *_DEFUN(ctime_r, (tim_p, result), _CONST time_t * tim_p _AND char *result) +{ + struct tm tm; + return asctime_r(localtime_r(tim_p, &tm), result); +} + +#endif diff --git a/linux-bsp/asm-study/myboot/include/linux/types.h b/linux-bsp/asm-study/myboot/include/linux/types.h new file mode 100644 index 0000000..c91b15e --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/linux/types.h @@ -0,0 +1,131 @@ +#ifndef _LINUX_TYPES_H +#define _LINUX_TYPES_H + +#ifdef __KERNEL__ +#include <linux/config.h> +#endif + +#include <linux/posix_types.h> +#include <asm/types.h> + +#ifndef __KERNEL_STRICT_NAMES + +typedef __kernel_fd_set fd_set; +typedef __kernel_dev_t dev_t; +typedef __kernel_ino_t ino_t; +typedef __kernel_mode_t mode_t; +typedef __kernel_nlink_t nlink_t; +typedef __kernel_off_t off_t; +typedef __kernel_pid_t pid_t; +typedef __kernel_daddr_t daddr_t; +typedef __kernel_key_t key_t; +typedef __kernel_suseconds_t suseconds_t; + +#ifdef __KERNEL__ +typedef __kernel_uid32_t uid_t; +typedef __kernel_gid32_t gid_t; +typedef __kernel_uid16_t uid16_t; +typedef __kernel_gid16_t gid16_t; + +#ifdef CONFIG_UID16 +/* This is defined by include/asm-{arch}/posix_types.h */ +typedef __kernel_old_uid_t old_uid_t; +typedef __kernel_old_gid_t old_gid_t; +#endif /* CONFIG_UID16 */ + +/* libc5 includes this file to define uid_t, thus uid_t can never change + * when it is included by non-kernel code + */ +#else +typedef __kernel_uid_t uid_t; +typedef __kernel_gid_t gid_t; +#endif /* __KERNEL__ */ + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __kernel_loff_t loff_t; +#endif + +/* + * The following typedefs are also protected by individual ifdefs for + * historical reasons: + */ +#ifndef _SIZE_T +#define _SIZE_T +typedef __kernel_size_t size_t; +#endif + +#ifndef _SSIZE_T +#define _SSIZE_T +typedef __kernel_ssize_t ssize_t; +#endif + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef __kernel_ptrdiff_t ptrdiff_t; +#endif + +#ifndef _TIME_T +#define _TIME_T +typedef __kernel_time_t time_t; +#endif + +#ifndef _CLOCK_T +#define _CLOCK_T +typedef __kernel_clock_t clock_t; +#endif + +#ifndef _CADDR_T +#define _CADDR_T +typedef __kernel_caddr_t caddr_t; +#endif + +/* bsd */ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +/* sysv */ +typedef unsigned char unchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ + +typedef __u8 u_int8_t; +typedef __s8 int8_t; +typedef __u16 u_int16_t; +typedef __s16 int16_t; +typedef __u32 u_int32_t; +typedef __s32 int32_t; + +#endif /* !(__BIT_TYPES_DEFINED__) */ + +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __u64 uint64_t; +typedef __u64 u_int64_t; +typedef __s64 int64_t; +#endif + +#endif /* __KERNEL_STRICT_NAMES */ + +/* + * Below are truly Linux-specific types that should never collide with + * any application/library that wants linux/types.h. + */ + +struct ustat +{ + __kernel_daddr_t f_tfree; + __kernel_ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + +#endif /* _LINUX_TYPES_H */ diff --git a/linux-bsp/asm-study/myboot/include/nand.h b/linux-bsp/asm-study/myboot/include/nand.h new file mode 100644 index 0000000..9269296 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/nand.h @@ -0,0 +1,271 @@ +/* + * linux/include/linux/mtd/nand.h + * + * Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org> + * Steven J. Hill <sjhill@realitydiluted.com> + * 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. + * + * Info: + * Contains standard defines and IDs for NAND flash devices + * + * Changelog: + * See git changelog. + */ +#ifndef __LINUX_MTD_NAND_H +#define __LINUX_MTD_NAND_H + +#include <common.h> +#include <linux/bitops.h> + +#define NAND_K9F2G08 0xecda + +/* This constant declares the max. oobsize / page, which + * is supported now. If you add a chip with bigger oobsize/page + * adjust this accordingly. + */ +#define NAND_MAX_OOBSIZE 218 +#define NAND_MAX_PAGESIZE 4096 + +/* + * Constants for hardware specific CLE/ALE/NCE function + * + * These are bits which can be or'ed to set/clear multiple + * bits in one go. + */ +/* Select the chip by setting nCE to low */ +#define NAND_NCE 0x01 +/* Select the command latch by setting CLE to high */ +#define NAND_CLE 0x02 +/* Select the address latch by setting ALE to high */ +#define NAND_ALE 0x04 + +#define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) +#define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) +#define NAND_CTRL_CHANGE 0x80 + +/* + * Standard NAND flash commands + */ +#define NAND_CMD_READ0 0x00 /*Page read period 1*/ +#define NAND_CMD_READSTART 0x30 /*Page read period 2, for large page*/ +#define NAND_CMD_READID 0x90 /*Read production ID*/ +#define NAND_CMD_SEQIN 0x80 /*Page write period 1*/ +#define NAND_CMD_PAGEPROG 0x10 /*Page write period 2*/ +#define NAND_CMD_ERASE1 0x60 /*Block erase period 1*/ +#define NAND_CMD_ERASE2 0xd0 /*Block erase period 2*/ +#define NAND_CMD_STATUS 0x70 /*Read status command*/ +#define NAND_CMD_RESET 0xff /*Nandflash reset command*/ +#define NAND_CMD_READ1 1 +#define NAND_CMD_RNDOUT 0x05 /*Page random read period 1*/ +#define NAND_CMD_RNDOUTSTART 0xE0 /*Page random read period 2*/ +#define NAND_CMD_RNDIN 0x85 /*Page random write*/ + +#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_STATUS_MULTI 0x71 + +/* Extended commands for large page devices */ +#define NAND_CMD_CACHEDPROG 0x15 + +/* Extended commands for AG-AND device */ +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but + * there is no way to distinguish that from NAND_CMD_READ0 + * until the remaining sequence of commands has been completed + * so add a high order bit and mask it off in the command. + */ +#define NAND_CMD_DEPLETE1 0x100 +#define NAND_CMD_DEPLETE2 0x38 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_STATUS_ERROR 0x72 +/* multi-bank error status (banks 0-3) */ +#define NAND_CMD_STATUS_ERROR0 0x73 +#define NAND_CMD_STATUS_ERROR1 0x74 +#define NAND_CMD_STATUS_ERROR2 0x75 +#define NAND_CMD_STATUS_ERROR3 0x76 +#define NAND_CMD_STATUS_RESET 0x7f +#define NAND_CMD_STATUS_CLEAR 0xff + +#define NAND_CMD_NONE -1 + +/* Status bits */ +#define NAND_STATUS_FAIL 0x01 +#define NAND_STATUS_FAIL_N1 0x02 +#define NAND_STATUS_TRUE_READY 0x20 +#define NAND_STATUS_READY 0x40 +#define NAND_STATUS_WP 0x80 + +/* + * Constants for ECC_MODES + */ +typedef enum +{ + NAND_ECC_NONE, + NAND_ECC_SOFT, + NAND_ECC_HW, + NAND_ECC_HW_SYNDROME, + NAND_ECC_HW_OOB_FIRST, +} nand_ecc_modes_t; + +/* + * Constants for Hardware ECC + */ +/* Reset Hardware ECC for read */ +#define NAND_ECC_READ 0 +/* Reset Hardware ECC for write */ +#define NAND_ECC_WRITE 1 +/* Enable Hardware ECC before syndrom is read back from flash */ +#define NAND_ECC_READSYN 2 + +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE 0x80 + +/* Option constants for bizarre disfunctionality and real +* features +*/ +/* Chip can not auto increment pages */ +#define NAND_NO_AUTOINCR 0x00000001 +/* Buswitdh is 16 bit */ +#define NAND_BUSWIDTH_16 0x00000002 +/* Device supports partial programming without padding */ +#define NAND_NO_PADDING 0x00000004 +/* Chip has cache program function */ +#define NAND_CACHEPRG 0x00000008 +/* Chip has copy back function */ +#define NAND_COPYBACK 0x00000010 +/* AND Chip which has 4 banks and a confusing page / block + * assignment. See Renesas datasheet for further information */ +#define NAND_IS_AND 0x00000020 +/* Chip has a array of 4 pages which can be read without + * additional ready /busy waits */ +#define NAND_4PAGE_ARRAY 0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others. */ +#define BBT_AUTO_REFRESH 0x00000080 +/* Chip does not require ready check on read. True + * for all large page devices, as they do not support + * autoincrement.*/ +#define NAND_NO_READRDY 0x00000100 +/* Chip does not allow subpage writes */ +#define NAND_NO_SUBPAGE_WRITE 0x00000200 + +/* Options valid for Samsung large page devices */ +#define NAND_SAMSUNG_LP_OPTIONS \ + (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK) + +/* Macros to identify the above */ +#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR)) +#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING)) +#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) +#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK)) +/* Large page NAND with SOFT_ECC should support subpage reads */ +#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \ + && (chip->page_shift > 9)) + +/* Mask to zero out the chip options, which come from the id table */ +#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) + +/* Non chip related options */ +/* Use a flash based bad block table. This option is passed to the + * default bad block table function. */ +#define NAND_USE_FLASH_BBT 0x00010000 +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN 0x00020000 +/* This option is defined if the board driver allocates its own buffers + (e.g. because it needs them DMA-coherent */ +#define NAND_OWN_BUFFERS 0x00040000 +/* Options set by nand scan */ +/* bbt has already been read */ +#define NAND_BBT_SCANNED 0x40000000 +/* Nand scan has allocated controller struct */ +#define NAND_CONTROLLER_ALLOC 0x80000000 + +/* Cell info constants */ +#define NAND_CI_CHIPNR_MSK 0x03 +#define NAND_CI_CELLTYPE_MSK 0x0C + +/* + * NAND Flash Manufacturer ID Codes + */ +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_MICRON 0x2c +#define NAND_MFR_AMD 0x01 + +/* +* Constants for oob configuration +*/ +#define NAND_SMALL_BADBLOCK_POS 5 +#define NAND_LARGE_BADBLOCK_POS 0 + + +#if defined(CONFIG_S3C2410) +#define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) +#define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x4) +#define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0x8) +#define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0xc) +#define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x10) +#define NFSTAT_BUSY 1 +#define nand_select() (REG_NFCONF &= ~0x800) /*Clear bit 11*/ +#define nand_deselect() (REG_NFCONF |= 0x800) +#define nand_clear_RnB() do {} while (0) +#define nand_detect_RnB() do {} while (0) +#define nand_wait_RnB() do {} while (0) + +#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) + +#define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) +#define REG_NFCONT __REGi(ELFIN_NAND_BASE + 0x4) +#define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x8) +#define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0xc) +#define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0x10) +#define REG_NFDATA16 __REGw(ELFIN_NAND_BASE + 0x10) +#define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x20) +#define NFSTAT_BUSY 1 +#define nand_select() (REG_NFCONT &= ~(1 << 1)) +#define nand_deselect() (REG_NFCONT |= (1 << 1)) +#define nand_clear_RnB() (REG_NFSTAT |= (1 << 2)) +#define nand_detect_RnB() {while(!(REG_NFSTAT&(1<<2)));} /*Wait Read & Busy signal goto high(not busy)*/ +#define nand_wait_RnB() {while(!(REG_NFSTAT&(1<<0)));} /*Wait nand flash not busy, wait bit[0] goes to 1*/ + +#endif + +#define SKIP_BAD_BLOCK 1 +#define NOT_SKIP_BAD_BLOCK 0 + +struct boot_nand_t +{ + int page_size; + int spare_size; + int block_size; + int block_num; + int bad_block_offset; + int id; + // unsigned long size; +}; + +int nand_init(struct boot_nand_t *nand); +int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); +int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); +int is_bad_block(struct boot_nand_t *nand, ulong addr); +int mark_bad_block(struct boot_nand_t *nand, ulong addr); +int nand_erase_block(struct boot_nand_t *nand, ulong block_num); +int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad); +void nand_scrub(struct boot_nand_t *nand); +int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); +int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); +int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); +int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); + + + +#endif /* __LINUX_MTD_NAND_H */ diff --git a/linux-bsp/asm-study/myboot/include/rsa.h b/linux-bsp/asm-study/myboot/include/rsa.h new file mode 100644 index 0000000..703ac7d --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/rsa.h @@ -0,0 +1,208 @@ +/** + * \file rsa.h + */ +#ifndef _RSA_H +#define _RSA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "bignum.h" + +#define ERR_RSA_BAD_INPUT_DATA 0x0300 +#define ERR_RSA_INVALID_PADDING 0x0310 +#define ERR_RSA_KEY_GEN_FAILED 0x0320 +#define ERR_RSA_KEY_CHK_FAILED 0x0330 +#define ERR_RSA_PUBLIC_FAILED 0x0340 +#define ERR_RSA_PRIVATE_FAILED 0x0350 +#define ERR_RSA_VERIFY_FAILED 0x0360 + +/* + * PKCS#1 stuff + */ +#define RSA_RAW 0 +#define RSA_MD2 2 +#define RSA_MD4 3 +#define RSA_MD5 4 +#define RSA_SHA1 5 + +#define RSA_SIGN 0x01 +#define RSA_CRYPT 0x02 + +/* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ +#define ASN1_HASH_MDX \ + "\x30\x20\x30\x0C\x06\x08\x2A\x86\x48" \ + "\x86\xF7\x0D\x02\x00\x05\x00\x04\x10" + +#define ASN1_HASH_SHA1 \ + "\x30\x21\x30\x09\x06\x05\x2B\x0E\x03" \ + "\x02\x1A\x05\x00\x04\x14" + +typedef struct +{ + int ver; /*!< should be 0 */ + int len; /*!< size(N) in chars */ + mpi N; /*!< public modulus */ + mpi E; /*!< public exponent */ + mpi D; /*!< private exponent */ + + mpi P; /*!< 1st prime factor */ + mpi Q; /*!< 2nd prime factor */ + mpi DP; /*!< D mod (P - 1) */ + mpi DQ; /*!< D mod (Q - 1) */ + mpi QP; /*!< inverse of Q % P */ + + mpi RN; /*!< cached R^2 mod N */ + mpi RP; /*!< cached R^2 mod P */ + mpi RQ; /*!< cached R^2 mod Q */ +} +rsa_context; + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context to be initialized + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * \param rng_f points to the RNG function + * \param rng_d points to the RNG data + * + * \return 0 if successful, or an ERR_RSA_XXX error code + */ +int rsa_gen_key( rsa_context *ctx, int nbits, int exponent, + int (*rng_f)(void *), void *rng_d ); + +/** + * \brief Perform an RSA public key operation + * + * \return 0 if successful, or an ERR_RSA_XXX error code + * + * \note This function does not take care of message + * padding: both ilen and olen must be equal to + * the modulus size (ctx->len). Also, be sure + * to set input[0] = 0. + */ +int rsa_public( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ); + +/** + * \brief Perform an RSA private key operation + * + * \return 0 if successful, or an ERR_RSA_XXX error code + * + * \note This function does not take care of message + * padding: both ilen and olen must be equal to + * the modulus size (ctx->len). Also, be sure + * to set input[0] = 0. + */ +int rsa_private( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ); + +/** + * \brief Return 0 if the public key is valid, + * or ERR_RSA_KEY_CHECK_FAILED + */ +int rsa_check_pubkey( rsa_context *ctx ); + +/** + * \brief Return 0 if the private key is valid, + * or ERR_RSA_KEY_CHECK_FAILED + */ +int rsa_check_privkey( rsa_context *ctx ); + +/** + * \brief Add the PKCS#1 v1.5 padding and do a public RSA + * + * \param ctx RSA context + * \param input buffer holding the data to be encrypted + * \param ilen length of the plaintext; cannot be longer + * than the modulus, minus 3+8 for padding + * \param output buffer that will hold the ciphertext + * \param olen must be the same as the modulus size + * (for example, 128 if RSA-1024 is used) + * + * \return 0 if successful, or an ERR_RSA_XXX error code + */ +int rsa_pkcs1_encrypt( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ); + +/** + * \brief Do a private RSA, removes the PKCS#1 v1.5 padding + * + * \param ctx RSA context + * \param input buffer holding the encrypted data + * \param ilen must be the same as the modulus size + * \param output buffer that will hold the plaintext + * \param olen size of output buffer, will be updated + * to contain the length of the plaintext + * + * \return 0 if successful, or an ERR_RSA_XXX error code + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ); + +/** + * \brief Perform a private RSA to sign a message digest + * + * \param ctx RSA context + * \param alg_id RSA_RAW, RSA_MD2/4/5 or RSA_SHA1 + * \param hash buffer holding the message digest + * \param hashlen message digest length + * \param sig buffer that will hold the ciphertext + * \param siglen must be the same as the modulus size + * (for example, 128 if RSA-1024 is used) + * + * \return 0 if the signing operation was successful, + * or an ERR_RSA_XXX error code + */ +int rsa_pkcs1_sign( rsa_context *ctx, int alg_id, + unsigned char *hash, int hashlen, + unsigned char *sig, int siglen ); + +/** + * \brief Perform a public RSA and check the message digest + * + * \param ctx points to an RSA public key + * \param alg_id RSA_RAW, RSA_MD2/4/5 or RSA_SHA1 + * \param hash buffer holding the message digest + * \param hashlen message digest length + * \param sig buffer holding the ciphertext + * \param siglen must be the same as the modulus size + * + * \return 0 if the verify operation was successful, + * or an ERR_RSA_XXX error code + */ +int rsa_pkcs1_verify( rsa_context *ctx, int alg_id, + unsigned char *hash, int hashlen, + unsigned char *sig, int siglen ); + +/** + * \brief Free the components of an RSA key + */ +void rsa_free( rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int rsa_self_test( void ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/linux-bsp/asm-study/myboot/include/s3c2440.h b/linux-bsp/asm-study/myboot/include/s3c2440.h new file mode 100644 index 0000000..308dc25 --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/s3c2440.h @@ -0,0 +1,674 @@ +/* + * (C) Copyright 2003 + * David M�ller ELSOFT AG Switzerland. d.mueller@elsoft.ch + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +/************************************************ + * NAME : s3c2440.h + * + * Based on S3C2440A User's manual Rev 1.1 + ************************************************/ + +#ifndef __S3C2440_H__ +#define __S3C2440_H__ + +/*This is debug on FL2440 board*/ +#define BEEP 0 /*Buzzer use GPB0 */ +#define LED0 5 /*LED0 use GPB5 */ +#define LED1 6 /*LED1 use GPB6 */ +#define LED2 8 /*LED2 use GPB8 */ +#define LED3 10 /*LED3 use GPB10 */ +/*FL2440 LED & Beep define end*/ + +#define S3C24X0_UART_CHANNELS 3 +#define S3C24X0_SPI_CHANNELS 2 + +#include <asm/hardware.h> + +#ifndef __ASSEMBLY__ +typedef enum +{ + S3C24X0_UART0, + S3C24X0_UART1, +} S3C24X0_UARTS_NR; + +#include <s3c24x0.h> +#endif + +#define ROM_BASE0 0x00000000 /* base address of rom bank 0 */ +#define ROM_BASE1 0x04000000 /* base address of rom bank 1 */ +#define DRAM_BASE0 0x30000000 /* base address of dram bank 0 */ +#define DRAM_BASE1 0x00000000 /* base address of dram bank 1 */ + +/* S3C2440 only supports 512 Byte HW ECC */ +#define S3C2410_ECCSIZE 512 +#define S3C2410_ECCBYTES 3 + +/* S3C2440 device base addresses */ +#define ELFIN_DMA_BASE 0x4b000000 +#define ELFIN_USB_DEVICE_BASE 0x44a00000 +#define ELFIN_I2C_BASE 0x54000000 +#define ELFIN_I2S_BASE 0x55000000 +#define ELFIN_ADC_BASE 0x58000000 +#define ELFIN_SPI_BASE 0x59000000 +#define ELFIN_SDI_BASE 0x5A000000 + +/* + * Memory controller + */ + +#define ELFIN_MEM_CON_BASE 0x48000000 + +#define BWSCON_OFFSET 0x00 +#define BANKCON0_OFFSET 0x04 +#define BANKCON1_OFFSET 0x08 +#define BANKCON2_OFFSET 0x0c +#define BANKCON3_OFFSET 0x10 +#define BANKCON4_OFFSET 0x14 +#define BANKCON5_OFFSET 0x18 +#define BANKCON6_OFFSET 0x1c +#define BANKCON7_OFFSET 0x20 +#define REFRESH_OFFSET 0x24 +#define BANKSIZE_OFFSET 0x28 +#define MRSRB6_OFFSET 0x2c +#define MRSRB7_OFFSET 0x30 + +#define BWSCON_REG __REG(0x48000000) +#define BANKCON0_REG __REG(0x48000004) +#define BANKCON1_REG __REG(0x48000008) +#define BANKCON2_REG __REG(0x4800000c) +#define BANKCON3_REG __REG(0x48000010) +#define BANKCON4_REG __REG(0x48000014) +#define BANKCON5_REG __REG(0x48000018) +#define BANKCON6_REG __REG(0x4800001c) +#define BANKCON7_REG __REG(0x48000020) +#define REFRESH_REG __REG(0x48000024) +#define BANKSIZE_REG __REG(0x48000028) +#define MRSRB6_REG __REG(0x4800002c) +#define MRSRB7_REG __REG(0x48000030) + +/* + * USB Host Controller + */ +#define ELFIN_USB_HOST_BASE 0x49000000 + +#define HcRevision_OFFSET 0x00 +#define HcControl_OFFSET 0x04 +#define HcCommonStatus_OFFSET 0x08 +#define HcIntStatus_OFFSET 0x0c +#define HcIntEnable_OFFSET 0x10 +#define HcIntDisable_OFFSET 0x14 +#define HcHCCA_OFFSET 0x18 +#define HcPerdCurED_OFFSET 0x1c +#define HcCtrlHeadED_OFFSET 0x20 +#define HcCtrlCurED_OFFSET 0x24 +#define HcBulkHeadED_OFFSET 0x28 +#define HcBulkCurED_OFFSET 0x2c +#define HcDoneHead_OFFSET 0x30 +#define HcRmInterval_OFFSET 0x34 +#define HcFmRemain_OFFSET 0x38 +#define HcFmNumber_OFFSET 0x3c +#define HcPerdStart_OFFSET 0x40 +#define HcLSThres_OFFSET 0x44 +#define HcRhDescA_OFFSET 0x48 +#define HcRhDescB_OFFSET 0x4c +#define HcRhStatus_OFFSET 0x50 +#define HcRhPortSts1_OFFSET 0x54 +#define HcRhPortSts2_OFFSET 0x58 + +#define HcRevision_REG __REG(0x49000000) +#define HcControl_REG __REG(0x49000004) +#define HcCommonStatus_REG __REG(0x49000008) +#define HcIntStatus_REG __REG(0x4900000c) +#define HcIntEnable_REG __REG(0x49000010) +#define HcIntDisable_REG __REG(0x49000014) +#define HcHCCA_REG __REG(0x49000018) +#define HcPerdCurED_REG __REG(0x4900001c) +#define HcCtrlHeadED_REG __REG(0x49000020) +#define HcCtrlCurED_REG __REG(0x49000024) +#define HcBulkHeadED_REG __REG(0x49000028) +#define HcBulkCurED_REG __REG(0x4900002c) +#define HcDoneHead_REG __REG(0x49000030) +#define HcRmInterval_REG __REG(0x49000034) +#define HcFmRemain_REG __REG(0x49000038) +#define HcFmNumber_REG __REG(0x4900003c) +#define HcPerdStart_REG __REG(0x49000040) +#define HcLSThres_REG __REG(0x49000044) +#define HcRhDescA_REG __REG(0x49000048) +#define HcRhDescB_REG __REG(0x4900004c) +#define HcRhStatus_REG __REG(0x49000050) +#define HcRhPortSts1_REG __REG(0x49000054) +#define HcRhPortSts2_REG __REG(0x49000058) + +/* + * Interrupt + */ +#define ELFIN_INTERRUPT_BASE 0x4a000000 + +#define SRCPND_OFFSET 0x00 +#define INTMOD_OFFSET 0x04 +#define INTMSK_OFFSET 0x08 +#define PRIORITY_OFFSET 0x0c +#define INTPND_OFFSET 0x10 +#define INTOFFSET_OFFSET 0x14 +#define SUBSRCPND_OFFSET 0x18 +#define INTSUBMSK_OFFSET 0x1c + +#define SRCPND_REG __REG(0x4a000000) +#define INTMOD_REG __REG(0x4a000004) +#define INTMSK_REG __REG(0x4a000008) +#define PRIORITY_REG __REG(0x4a00000c) +#define INTPND_REG __REG(0x4a000010) +#define INTOFFSET_REG __REG(0x4a000014) +#define SUBSRCPND_REG __REG(0x4a000018) +#define INTSUBMSK_REG __REG(0x4a00001C) + +/* + * Clock and power management + */ + +#define ELFIN_CLOCK_POWER_BASE 0x4c000000 + +#define LOCKTIME_OFFSET 0x00 +#define MPLLCON_OFFSET 0x04 +#define UPLLCON_OFFSET 0x08 +#define CLKCON_OFFSET 0x0c +#define CLKSLOW_OFFSET 0x10 +#define CLKDIVN_OFFSET 0x14 +#define CAMDIVN_OFFSET 0x18 + +#define LOCKTIME_REG __REG(0x4c000000) +#define MPLLCON_REG __REG(0x4c000004) +#define UPLLCON_REG __REG(0x4c000008) +#define CLKCON_REG __REG(0x4c00000c) +#define CLKSLOW_REG __REG(0x4c000010) +#define CLKDIVN_REG __REG(0x4c000014) +#define CAMDIVN_REG __REG(0x4c000018) + +/* + * LCD Controller + */ +#define ELFIN_LCD_BASE 0x4d000000 + +/* + * GPIO + */ + +#define ELFIN_GPIO_BASE 0x56000000 + +#define GPACON_OFFSET 0x00 +#define GPADAT_OFFSET 0x04 +#define GPAPU_OFFSET 0x08 +#define GPASLPCON_OFFSET 0x0C +#define GPABON_OFFSET 0x10 +#define GPBDAT_OFFSET 0x14 +#define GPBPU_OFFSET 0x18 +#define GPBSLPCON_OFFSET 0x1C +#define GPCCON_OFFSET 0x20 +#define GPCDAT_OFFSET 0x24 +#define GPCPU_OFFSET 0x28 +#define GPCSLPCON_OFFSET 0x2C +#define GPDCON_OFFSET 0x30 +#define GPDDAT_OFFSET 0x34 +#define GPDPU_OFFSET 0x38 +#define GPECON_OFFSET 0x40 +#define GPEDAT_OFFSET 0x44 +#define GPEPU_OFFSET 0x48 +#define GPESLPCON_OFFSET 0x4C +#define GPFCON_OFFSET 0x50 +#define GPFDAT_OFFSET 0x54 +#define GPFPU_OFFSET 0x58 +#define GPFSLPCON_OFFSET 0x5C +#define GPGCON_OFFSET 0x60 +#define GPGDAT_OFFSET 0x64 +#define GPGPU_OFFSET 0x68 +#define GPGSLPCON_OFFSET 0x6C +#define GPHCON_OFFSET 0x70 +#define GPHDAT_OFFSET 0x74 +#define GPHPU_OFFSET 0x78 +#define GPHSLPCON_OFFSET 0x7C +#define GPICON_OFFSET 0x80 +#define GPIDAT_OFFSET 0x84 +#define GPIPU_OFFSET 0x88 +#define GPISLPCON_OFFSET 0x8C +#define GPJCON_OFFSET 0x90 +#define GPJDAT_OFFSET 0x94 +#define GPJPU_OFFSET 0x98 +#define SPCON_OFFSET 0x9C +#define GPKCON_OFFSET 0xA0 +#define GPKDAT_OFFSET 0xA4 +#define GPKPU_OFFSET 0xA8 +#define GPKSLPCON_OFFSET 0xAC +#define EINTCON0_OFFSET 0xB0 +#define EINTCON1_OFFSET 0xB4 +#define EINTFLT0_OFFSET 0xB8 +#define EINTFLT1_OFFSET 0xBC +#define EINTMASK_OFFSET 0xC0 +#define EINTPEND_OFFSET 0xC4 +#define DSPGPSLP_OFFSET 0xC8 +#define MEM0CONSTOP_OFFSET 0xD0 +#define MEM1CONSTOP_OFFSET 0xD4 +#define MEM2CONSTOP_OFFSET 0xD8 +#define MEM0CONSLP_OFFSET 0xE0 +#define MEM1CONSLP_OFFSET 0xE4 +#define MEM2CONSLP_OFFSET 0xE8 +#define SPCONSLP_OFFSET 0xEC +#define SLPEN_OFFSET 0xF0 +#define MEM0DRVCON_OFFSET 0xF4 +#define MEM1DRVCON_OFFSET 0xF8 +#define MEM2DRVCON_OFFSET 0xFC + +#define GPACON_REG __REG(0x44800000) +#define GPADAT_REG __REG(0x44800004) +#define GPAPU_REG __REG(0x44800008) +#define GPASLPCON_REG __REG(0x4480000C) +#define GPABON_REG __REG(0x44800010) +#define GPBDAT_REG __REG(0x44800014) +#define GPBPU_REG __REG(0x44800018) +#define GPBSLPCON_REG __REG(0x4480001C) +#define GPCCON_REG __REG(0x44800020) +#define GPCDAT_REG __REG(0x44800024) +#define GPCPU_REG __REG(0x44800028) +#define GPCSLPCON_REG __REG(0x4480002C) +#define GPDCON_REG __REG(0x44800030) +#define GPDDAT_REG __REG(0x44800034) +#define GPDPU_REG __REG(0x44800038) +#define GPECON_REG __REG(0x44800040) +#define GPEDAT_REG __REG(0x44800044) +#define GPEPU_REG __REG(0x44800048) +#define GPESLPCON_REG __REG(0x4480004C) +#define GPFCON_REG __REG(0x44800050) +#define GPFDAT_REG __REG(0x44800054) +#define GPFPU_REG __REG(0x44800058) +#define GPFSLPCON_REG __REG(0x4480005C) +#define GPGCON_REG __REG(0x44800060) +#define GPGDAT_REG __REG(0x44800064) +#define GPGPU_REG __REG(0x44800068) +#define GPGSLPCON_REG __REG(0x4480006C) +#define GPHCON_REG __REG(0x44800070) +#define GPHDAT_REG __REG(0x44800074) +#define GPHPU_REG __REG(0x44800078) +#define GPHSLPCON_REG __REG(0x4480007C) +#define GPICON_REG __REG(0x44800080) +#define GPIDAT_REG __REG(0x44800084) +#define GPIPU_REG __REG(0x44800088) +#define GPISLPCON_REG __REG(0x4480008C) +#define GPJCON_REG __REG(0x44800090) +#define GPJDAT_REG __REG(0x44800094) +#define GPJPU_REG __REG(0x44800098) +#define SPCON_REG __REG(0x4480009C) +#define GPKCON_REG __REG(0x448000A0) +#define GPKDAT_REG __REG(0x448000A4) +#define GPKPU_REG __REG(0x448000A8) +#define GPKSLPCON_REG __REG(0x448000AC) +#define EINTCON0_REG __REG(0x448000B0) +#define EINTCON1_REG __REG(0x448000B4) +#define EINTFLT0_REG __REG(0x448000B8) +#define EINTFLT1_REG __REG(0x448000BC) +#define EINTMASK_REG __REG(0x448000C0) +#define EINTPEND_REG __REG(0x448000C4) +#define DSPGPSLP_REG __REG(0x448000C8) +#define MEM0CONSTOP_REG __REG(0x448000D0) +#define MEM1CONSTOP_REG __REG(0x448000D4) +#define MEM2CONSTOP_REG __REG(0x448000D8) +#define MEM0CONSLP_REG __REG(0x448000E0) +#define MEM1CONSLP_REG __REG(0x448000E4) +#define MEM2CONSLP_REG __REG(0x448000E8) +#define SPCONSLP_REG __REG(0x448000EC) +#define SLPEN_REG __REG(0x448000F0) +#define MEM0DRVCON_REG __REG(0x448000F4) +#define MEM1DRVCON_REG __REG(0x448000F8) +#define MEM2DRVCON_REG __REG(0x448000FC) + +/* + * Nand flash controller + */ + +#define ELFIN_NAND_BASE 0x4e000000 + +#define NFCONF_OFFSET 0x00 +#define NFCONT_OFFSET 0x04 +#define NFCMMD_OFFSET 0x08 +#define NFADDR_OFFSET 0x0c +#define NFDATA_OFFSET 0x10 +#define NFMECCD0_OFFSET 0x14 +#define NFMECCD1_OFFSET 0x18 +#define NFSECCD_OFFSET 0x1c +#define NFSTAT_OFFSET 0x20 +#define NFESTAT0_OFFSET 0x24 +#define NFESTAT1_OFFSET 0x28 +#define NFMECC0_OFFSET 0x2c +#define NFMECC1_OFFSET 0x30 +#define NFSECC_OFFSET 0x34 +#define NFSBLK_OFFSET 0x38 +#define NFEBLK_OFFSET 0x3c + +#define NFCONF (0x4e000000) +#define NFCONT (0x4e000004) +#define NFCMMD (0x4e000008) +#define NFADDR (0x4e00000C) +#define NFDATA (0x4e000010) +#define NFMECCDATA0 (0x4e000014) +#define NFMECCDATA1 (0x4e000018) +#define NFSECCDATA (0x4e00001c) +#define NFSTAT (0x4e000020) +#define NFESTAT0 (0x4e000024) +#define NFESTAT1 (0x4e000028) +#define NFMECC0 (0x4e00002C) +#define NFMECC1 (0x4e000030) +#define NFSECC (0x4e00003c) + +#define NFCONF_REG __REG(0x4e000000) +#define NFCONT_REG __REG(0x4e000004) +#define NFCMD_REG __REGb(0x4e000008) +#define NFADDR_REG __REGb(0x4e00000C) +#define NFDATA8_REG __REGb(0x4e000010) +#define NFDATA16_REG __REGw(0x4e000010) +#define NFDATA32_REG __REG(0x4e000010) +#define NFSTAT_REG __REG(0x4e000020) + +#define NFCONT_WP (1<<12) +#define NFCONT_SECCLOCK (1<<6) +#define NFCONT_MECCLOCK (1<<5) +#define NFCONT_INITECC (1<<4) +#define NFCONT_CS_ALT (1<<1) +#define NFCONT_CS (1<<1) +#define NFSTAT_RnB (1<<0) + +/* + * Watchdog timer + */ + +#define ELFIN_WATCHDOG_BASE 0x53000000 + +#define WTCON_OFFSET 0x00 +#define WTDAT_OFFSET 0x04 +#define WTCNT_OFFSET 0x08 + +#define WTCON_REG __REG(0x53000000) +#define WTDAT_REG __REG(0x53000004) +#define WTCNT_REG __REG(0x53000008) + +/* + * UART + */ +#define ELFIN_UART_BASE 0x50000000 + +#define ULCON0_OFFSET 0x00 +#define UCON0_OFFSET 0x04 +#define UFCON0_OFFSET 0x08 +#define UMCON0_OFFSET 0x0C +#define UTRSTAT0_OFFSET 0x10 +#define UERSTAT0_OFFSET 0x14 +#define UFSTAT0_OFFSET 0x18 +#define UMSTAT0_OFFSET 0x1C +#define UTXH0_OFFSET 0x20 +#define URXH0_OFFSET 0x24 +#define UBRDIV0_OFFSET 0x28 + +#define ULCON0_REG __REG(0x50000000) +#define UCON0_REG __REG(0x50000004) +#define UFCON0_REG __REG(0x50000008) +#define UMCON0_REG __REG(0x5000000C) +#define UTRSTAT0_REG __REG(0x50000010) +#define UERSTAT0_REG __REG(0x50000014) +#define UFSTAT0_REG __REG(0x50000018) +#define UMSTAT0_REG __REG(0x5000001C) +#define UTXH0_REG __REG(0x50000020) +#define URXH0_REG __REG(0x50000024) +#define UBRDIV0_REG __REG(0x50000028) + +#define ULCON1_REG __REG(0x50004000) +#define UCON1_REG __REG(0x50004004) +#define UFCON1_REG __REG(0x50004008) +#define UMCON1_REG __REG(0x5000400C) +#define UTRSTAT1_REG __REG(0x50004010) +#define UERSTAT1_REG __REG(0x50004014) +#define UFSTAT1_REG __REG(0x50004018) +#define UMSTAT1_REG __REG(0x5000401C) +#define UTXH1_REG __REG(0x50004020) +#define URXH1_REG __REG(0x50004024) +#define UBRDIV1_REG __REG(0x50004028) + +#define ULCON2_REG __REG(0x50008000) +#define UCON2_REG __REG(0x50008004) +#define UFCON2_REG __REG(0x50008008) +#define UMCON2_REG __REG(0x5000800C) +#define UTRSTAT2_REG __REG(0x50008010) +#define UERSTAT2_REG __REG(0x50008014) +#define UFSTAT2_REG __REG(0x50008018) +#define UMSTAT2_REG __REG(0x5000801C) +#define UTXH2_REG __REG(0x50008020) +#define URXH2_REG __REG(0x50008024) +#define UBRDIV2_REG __REG(0x50008028) + +#define UTRSTAT_TX_EMPTY (1 << 2) +#define UTRSTAT_RX_READY (1 << 0) +#define UART_ERR_MASK 0xF + +/* + * PWM timer + */ +#define ELFIN_TIMER_BASE 0x51000000 + +#define TCFG0_REG __REG(0x51000000) +#define TCFG1_REG __REG(0x51000004) +#define TCON_REG __REG(0x51000008) +#define TCNTB0_REG __REG(0x5100000C) +#define TCMPB0_REG __REG(0x51000010) +#define TCNTO0_REG __REG(0x51000014) +#define TCNTB1_REG __REG(0x51000018) +#define TCMPB1_REG __REG(0x5100001C) +#define TCNTO1_REG __REG(0x51000020) +#define TCNTB2_REG __REG(0x51000024) +#define TCMPB2_REG __REG(0x51000028) +#define TCNTO2_REG __REG(0x5100002C) +#define TCNTB3_REG __REG(0x51000030) +#define TCMPB3_REG __REG(0x51000034) +#define TCNTO3_REG __REG(0x51000038) +#define TCNTB4_REG __REG(0x5100003C) +#define TCNTO4_REG __REG(0x51000040) + +/* Fields */ +#define fTCFG0_DZONE Fld(8,16) /* the dead zone length (= timer 0) */ +#define fTCFG0_PRE1 Fld(8,8) /* prescaler value for time 2,3,4 */ +#define fTCFG0_PRE0 Fld(8,0) /* prescaler value for time 0,1 */ +#define fTCFG1_MUX4 Fld(4,16) +/* bits */ +#define TCFG0_DZONE(x) FInsrt((x), fTCFG0_DZONE) +#define TCFG0_PRE1(x) FInsrt((x), fTCFG0_PRE1) +#define TCFG0_PRE0(x) FInsrt((x), fTCFG0_PRE0) +#define TCON_4_AUTO (1 << 22) /* auto reload on/off for Timer 4 */ +#define TCON_4_UPDATE (1 << 21) /* manual Update TCNTB4 */ +#define TCON_4_ONOFF (1 << 20) /* 0: Stop, 1: start Timer 4 */ +#define COUNT_4_ON (TCON_4_ONOFF*1) +#define COUNT_4_OFF (TCON_4_ONOFF*0) +#define TCON_3_AUTO (1 << 19) /* auto reload on/off for Timer 3 */ +#define TIMER3_ATLOAD_ON (TCON_3_AUTO*1) +#define TIMER3_ATLAOD_OFF FClrBit(TCON, TCON_3_AUTO) +#define TCON_3_INVERT (1 << 18) /* 1: Inverter on for TOUT3 */ +#define TIMER3_IVT_ON (TCON_3_INVERT*1) +#define TIMER3_IVT_OFF (FClrBit(TCON, TCON_3_INVERT)) +#define TCON_3_MAN (1 << 17) /* manual Update TCNTB3,TCMPB3 */ +#define TIMER3_MANUP (TCON_3_MAN*1) +#define TIMER3_NOP (FClrBit(TCON, TCON_3_MAN)) +#define TCON_3_ONOFF (1 << 16) /* 0: Stop, 1: start Timer 3 */ +#define TIMER3_ON (TCON_3_ONOFF*1) +#define TIMER3_OFF (FClrBit(TCON, TCON_3_ONOFF)) +/* macros */ +#define GET_PRESCALE_TIMER4(x) FExtr((x), fTCFG0_PRE1) +#define GET_DIVIDER_TIMER4(x) FExtr((x), fTCFG1_MUX4) + +/* + * RTC Controller + */ +#define ELFIN_RTC_BASE 0x57000000 +#define RTCCON_REG __REG(0x57000040) +#define TICNT_REG __REG(0x57000044) +#define RTCALM_REG __REG(0x57000050) +#define ALMSEC_REG __REG(0x57000054) +#define ALMMIN_REG __REG(0x57000058) +#define ALMHOUR_REG __REG(0x5700005c) +#define ALMDATE_REG __REG(0x57000060) +#define ALMMON_REG __REG(0x57000064) +#define ALMYEAR_REG __REG(0x57000068) +#define BCDSEC_REG __REG(0x57000070) +#define BCDMIN_REG __REG(0x57000074) +#define BCDHOUR_REG __REG(0x57000078) +#define BCDDATE_REG __REG(0x5700007c) +#define BCDDAY_REG __REG(0x57000080) +#define BCDMON_REG __REG(0x57000084) +#define BCDYEAR_REG __REG(0x57000088) + +/* USB Device */ +#define ELFIN_USBD_BASE 0x52000000 +#define USB_DEVICE_PHYS_ADR ELFIN_USBD_BASE + +/* include common stuff */ +#ifndef __ASSEMBLY__ +static inline S3C24X0_MEMCTL *S3C24X0_GetBase_MEMCTL(void) +{ + return (S3C24X0_MEMCTL *) (ELFIN_MEM_CON_BASE); +} +static inline S3C24X0_USB_HOST *S3C24X0_GetBase_USB_HOST(void) +{ + return (S3C24X0_USB_HOST *) ELFIN_USB_HOST_BASE; +} +static inline S3C24X0_INTERRUPT *S3C24X0_GetBase_INTERRUPT(void) +{ + return (S3C24X0_INTERRUPT *) ELFIN_INTERRUPT_BASE; +} +static inline S3C24X0_DMAS *S3C24X0_GetBase_DMAS(void) +{ + return (S3C24X0_DMAS *) ELFIN_DMA_BASE; +} +static inline S3C24X0_CLOCK_POWER *S3C24X0_GetBase_CLOCK_POWER(void) +{ + return (S3C24X0_CLOCK_POWER *) ELFIN_CLOCK_POWER_BASE; +} +static inline S3C24X0_LCD *S3C24X0_GetBase_LCD(void) +{ + return (S3C24X0_LCD *) ELFIN_LCD_BASE; +} +static inline S3C2410_NAND *S3C2410_GetBase_NAND(void) +{ + return (S3C2410_NAND *) ELFIN_NAND_BASE; +} +static inline S3C24X0_UART *S3C24X0_GetBase_UART(S3C24X0_UARTS_NR nr) +{ + return (S3C24X0_UART *) (ELFIN_UART_BASE + (nr * 0x4000)); +} +static inline S3C24X0_TIMERS *S3C24X0_GetBase_TIMERS(void) +{ + return (S3C24X0_TIMERS *) ELFIN_TIMER_BASE; +} +static inline S3C24X0_USB_DEVICE *S3C24X0_GetBase_USB_DEVICE(void) +{ + return (S3C24X0_USB_DEVICE *) ELFIN_USB_DEVICE_BASE; +} +static inline S3C24X0_WATCHDOG *S3C24X0_GetBase_WATCHDOG(void) +{ + return (S3C24X0_WATCHDOG *) ELFIN_WATCHDOG_BASE; +} +static inline S3C24X0_I2C *S3C24X0_GetBase_I2C(void) +{ + return (S3C24X0_I2C *) ELFIN_I2C_BASE; +} +static inline S3C24X0_I2S *S3C24X0_GetBase_I2S(void) +{ + return (S3C24X0_I2S *) ELFIN_I2S_BASE; +} +static inline S3C24X0_GPIO *S3C24X0_GetBase_GPIO(void) +{ + return (S3C24X0_GPIO *) ELFIN_GPIO_BASE; +} +static inline S3C24X0_RTC *S3C24X0_GetBase_RTC(void) +{ + return (S3C24X0_RTC *) ELFIN_RTC_BASE; +} +static inline S3C2410_ADC *S3C2410_GetBase_ADC(void) +{ + return (S3C2410_ADC *) ELFIN_ADC_BASE; +} +static inline S3C24X0_SPI *S3C24X0_GetBase_SPI(void) +{ + return (S3C24X0_SPI *) ELFIN_SPI_BASE; +} +static inline S3C2410_SDI *S3C2410_GetBase_SDI(void) +{ + return (S3C2410_SDI *) ELFIN_SDI_BASE; +} +#else /* #ifndef __ASSEMBLY__ */ + +/* watchdog */ +#define WTCON_OFFSET 0x00 + +/* LCD controller */ +#define LCDBGCON_OFFSET 0x5c + +#endif /* #ifndef __ASSEMBLY__ */ + +/* PENDING BIT */ +#define BIT_EINT0 (0x1) +#define BIT_EINT1 (0x1<<1) +#define BIT_EINT2 (0x1<<2) +#define BIT_EINT3 (0x1<<3) +#define BIT_EINT4_7 (0x1<<4) +#define BIT_EINT8_23 (0x1<<5) +#define BIT_BAT_FLT (0x1<<7) +#define BIT_TICK (0x1<<8) +#define BIT_WDT (0x1<<9) +#define BIT_TIMER0 (0x1<<10) +#define BIT_TIMER1 (0x1<<11) +#define BIT_TIMER2 (0x1<<12) +#define BIT_TIMER3 (0x1<<13) +#define BIT_TIMER4 (0x1<<14) +#define BIT_UART2 (0x1<<15) +#define BIT_LCD (0x1<<16) +#define BIT_DMA0 (0x1<<17) +#define BIT_DMA1 (0x1<<18) +#define BIT_DMA2 (0x1<<19) +#define BIT_DMA3 (0x1<<20) +#define BIT_SDI (0x1<<21) +#define BIT_SPI0 (0x1<<22) +#define BIT_UART1 (0x1<<23) +#define BIT_USBH (0x1<<26) +#define BIT_IIC (0x1<<27) +#define BIT_UART0 (0x1<<28) +#define BIT_SPI1 (0x1<<29) +#define BIT_RTC (0x1<<30) +#define BIT_ADC (0x1<<31) +#define BIT_ALLMSK (0xFFFFFFFF) + +#define CLKCON_USBD (1<< 15) +#define BIT19 0x00080000 +#define BIT29 0x20000000 +#define BIT_USBD BIT29 +#define BIT_USBD_SUB BIT19 + +#define ClearPending(bit) {\ + rSRCPND = bit;\ + rINTPND = bit;\ + rINTPND;\ + } +/* Wait until rINTPND is changed for the case that the ISR is very short. */ + +#endif /*__S3C2440_H__*/ diff --git a/linux-bsp/asm-study/myboot/include/s3c24x0.h b/linux-bsp/asm-study/myboot/include/s3c24x0.h new file mode 100644 index 0000000..b0e1a7d --- /dev/null +++ b/linux-bsp/asm-study/myboot/include/s3c24x0.h @@ -0,0 +1,1125 @@ +/* + * (C) Copyright 2003 + * David M�ller ELSOFT AG Switzerland. d.mueller@elsoft.ch + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +/************************************************ + * NAME : s3c24x0.h + * Version : 31.3.2003 + * + * common stuff for SAMSUNG S3C24X0 SoC + ************************************************/ + +#ifndef __S3C24X0_H__ +#define __S3C24X0_H__ + +#include <asm/types.h> + +typedef volatile u8 S3C24X0_REG8; +typedef volatile u16 S3C24X0_REG16; +typedef volatile u32 S3C24X0_REG32; + +/* Memory controller (see manual chapter 5) */ +typedef struct +{ + S3C24X0_REG32 BWSCON; + S3C24X0_REG32 BANKCON[8]; + S3C24X0_REG32 REFRESH; + S3C24X0_REG32 BANKSIZE; + S3C24X0_REG32 MRSRB6; + S3C24X0_REG32 MRSRB7; +} /*__attribute__((__packed__))*/ S3C24X0_MEMCTL; + +/* USB HOST (see manual chapter 12) */ +typedef struct +{ + S3C24X0_REG32 HcRevision; + S3C24X0_REG32 HcControl; + S3C24X0_REG32 HcCommonStatus; + S3C24X0_REG32 HcInterruptStatus; + S3C24X0_REG32 HcInterruptEnable; + S3C24X0_REG32 HcInterruptDisable; + S3C24X0_REG32 HcHCCA; + S3C24X0_REG32 HcPeriodCuttendED; + S3C24X0_REG32 HcControlHeadED; + S3C24X0_REG32 HcControlCurrentED; + S3C24X0_REG32 HcBulkHeadED; + S3C24X0_REG32 HcBuldCurrentED; + S3C24X0_REG32 HcDoneHead; + S3C24X0_REG32 HcRmInterval; + S3C24X0_REG32 HcFmRemaining; + S3C24X0_REG32 HcFmNumber; + S3C24X0_REG32 HcPeriodicStart; + S3C24X0_REG32 HcLSThreshold; + S3C24X0_REG32 HcRhDescriptorA; + S3C24X0_REG32 HcRhDescriptorB; + S3C24X0_REG32 HcRhStatus; + S3C24X0_REG32 HcRhPortStatus1; + S3C24X0_REG32 HcRhPortStatus2; +} /*__attribute__((__packed__))*/ S3C24X0_USB_HOST; + +/* INTERRUPT (see manual chapter 14) */ +typedef struct +{ + S3C24X0_REG32 SRCPND; + S3C24X0_REG32 INTMOD; + S3C24X0_REG32 INTMSK; + S3C24X0_REG32 PRIORITY; + S3C24X0_REG32 INTPND; + S3C24X0_REG32 INTOFFSET; +#ifdef CONFIG_S3C2410 + S3C24X0_REG32 SUBSRCPND; + S3C24X0_REG32 INTSUBMSK; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_INTERRUPT; + +/* DMAS (see manual chapter 8) */ +typedef struct +{ + S3C24X0_REG32 DISRC; +#ifdef CONFIG_S3C2410 + S3C24X0_REG32 DISRCC; +#endif + S3C24X0_REG32 DIDST; +#ifdef CONFIG_S3C2410 + S3C24X0_REG32 DIDSTC; +#endif + S3C24X0_REG32 DCON; + S3C24X0_REG32 DSTAT; + S3C24X0_REG32 DCSRC; + S3C24X0_REG32 DCDST; + S3C24X0_REG32 DMASKTRIG; +#ifdef CONFIG_S3C2400 + S3C24X0_REG32 res[1]; +#endif +#ifdef CONFIG_S3C2410 + S3C24X0_REG32 res[7]; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_DMA; + +typedef struct +{ + S3C24X0_DMA dma[4]; +} /*__attribute__((__packed__))*/ S3C24X0_DMAS; + +/* CLOCK & POWER MANAGEMENT (see S3C2400 manual chapter 6) */ +/* (see S3C2410 manual chapter 7) */ +typedef struct +{ + S3C24X0_REG32 LOCKTIME; + S3C24X0_REG32 MPLLCON; + S3C24X0_REG32 UPLLCON; + S3C24X0_REG32 CLKCON; + S3C24X0_REG32 CLKSLOW; + S3C24X0_REG32 CLKDIVN; +} /*__attribute__((__packed__))*/ S3C24X0_CLOCK_POWER; + +/* LCD CONTROLLER (see manual chapter 15) */ +typedef struct +{ + S3C24X0_REG32 LCDCON1; + S3C24X0_REG32 LCDCON2; + S3C24X0_REG32 LCDCON3; + S3C24X0_REG32 LCDCON4; + S3C24X0_REG32 LCDCON5; + S3C24X0_REG32 LCDSADDR1; + S3C24X0_REG32 LCDSADDR2; + S3C24X0_REG32 LCDSADDR3; + S3C24X0_REG32 REDLUT; + S3C24X0_REG32 GREENLUT; + S3C24X0_REG32 BLUELUT; + S3C24X0_REG32 res[8]; + S3C24X0_REG32 DITHMODE; + S3C24X0_REG32 TPAL; +#ifdef CONFIG_S3C2410 + S3C24X0_REG32 LCDINTPND; + S3C24X0_REG32 LCDSRCPND; + S3C24X0_REG32 LCDINTMSK; + S3C24X0_REG32 LPCSEL; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_LCD; + +/* NAND FLASH (see S3C2410 manual chapter 6) */ +typedef struct +{ + S3C24X0_REG32 NFCONF; + S3C24X0_REG32 NFCMD; + S3C24X0_REG32 NFADDR; + S3C24X0_REG32 NFDATA; + S3C24X0_REG32 NFSTAT; + S3C24X0_REG32 NFECC; +} /*__attribute__((__packed__))*/ S3C2410_NAND; + +/* UART (see manual chapter 11) */ +typedef struct +{ + S3C24X0_REG32 ULCON; + S3C24X0_REG32 UCON; + S3C24X0_REG32 UFCON; + S3C24X0_REG32 UMCON; + S3C24X0_REG32 UTRSTAT; + S3C24X0_REG32 UERSTAT; + S3C24X0_REG32 UFSTAT; + S3C24X0_REG32 UMSTAT; +#ifdef __BIG_ENDIAN + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 UTXH; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 URXH; +#else /* Little Endian */ + S3C24X0_REG8 UTXH; + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 URXH; + S3C24X0_REG8 res2[3]; +#endif + S3C24X0_REG32 UBRDIV; +} /*__attribute__((__packed__))*/ S3C24X0_UART; + +/* PWM TIMER (see manual chapter 10) */ +typedef struct +{ + S3C24X0_REG32 TCNTB; + S3C24X0_REG32 TCMPB; + S3C24X0_REG32 TCNTO; +} /*__attribute__((__packed__))*/ S3C24X0_TIMER; + +typedef struct +{ + S3C24X0_REG32 TCFG0; + S3C24X0_REG32 TCFG1; + S3C24X0_REG32 TCON; + S3C24X0_TIMER ch[4]; + S3C24X0_REG32 TCNTB4; + S3C24X0_REG32 TCNTO4; +} /*__attribute__((__packed__))*/ S3C24X0_TIMERS; + +/* USB DEVICE (see manual chapter 13) */ +typedef struct +{ +#ifdef __BIG_ENDIAN + S3C24X0_REG8 res[3]; + S3C24X0_REG8 EP_FIFO_REG; +#else /* little endian */ + S3C24X0_REG8 EP_FIFO_REG; + S3C24X0_REG8 res[3]; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_USB_DEV_FIFOS; + +typedef struct +{ +#ifdef __BIG_ENDIAN + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 EP_DMA_CON; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 EP_DMA_UNIT; + S3C24X0_REG8 res3[3]; + S3C24X0_REG8 EP_DMA_FIFO; + S3C24X0_REG8 res4[3]; + S3C24X0_REG8 EP_DMA_TTC_L; + S3C24X0_REG8 res5[3]; + S3C24X0_REG8 EP_DMA_TTC_M; + S3C24X0_REG8 res6[3]; + S3C24X0_REG8 EP_DMA_TTC_H; +#else /* little endian */ + S3C24X0_REG8 EP_DMA_CON; + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 EP_DMA_UNIT; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 EP_DMA_FIFO; + S3C24X0_REG8 res3[3]; + S3C24X0_REG8 EP_DMA_TTC_L; + S3C24X0_REG8 res4[3]; + S3C24X0_REG8 EP_DMA_TTC_M; + S3C24X0_REG8 res5[3]; + S3C24X0_REG8 EP_DMA_TTC_H; + S3C24X0_REG8 res6[3]; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_USB_DEV_DMAS; + +typedef struct +{ +#ifdef __BIG_ENDIAN + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 FUNC_ADDR_REG; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 PWR_REG; + S3C24X0_REG8 res3[3]; + S3C24X0_REG8 EP_INT_REG; + S3C24X0_REG8 res4[15]; + S3C24X0_REG8 USB_INT_REG; + S3C24X0_REG8 res5[3]; + S3C24X0_REG8 EP_INT_EN_REG; + S3C24X0_REG8 res6[15]; + S3C24X0_REG8 USB_INT_EN_REG; + S3C24X0_REG8 res7[3]; + S3C24X0_REG8 FRAME_NUM1_REG; + S3C24X0_REG8 res8[3]; + S3C24X0_REG8 FRAME_NUM2_REG; + S3C24X0_REG8 res9[3]; + S3C24X0_REG8 INDEX_REG; + S3C24X0_REG8 res10[7]; + S3C24X0_REG8 MAXP_REG; + S3C24X0_REG8 res11[3]; + S3C24X0_REG8 EP0_CSR_IN_CSR1_REG; + S3C24X0_REG8 res12[3]; + S3C24X0_REG8 IN_CSR2_REG; + S3C24X0_REG8 res13[7]; + S3C24X0_REG8 OUT_CSR1_REG; + S3C24X0_REG8 res14[3]; + S3C24X0_REG8 OUT_CSR2_REG; + S3C24X0_REG8 res15[3]; + S3C24X0_REG8 OUT_FIFO_CNT1_REG; + S3C24X0_REG8 res16[3]; + S3C24X0_REG8 OUT_FIFO_CNT2_REG; +#else /* little endian */ + S3C24X0_REG8 FUNC_ADDR_REG; + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 PWR_REG; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 EP_INT_REG; + S3C24X0_REG8 res3[15]; + S3C24X0_REG8 USB_INT_REG; + S3C24X0_REG8 res4[3]; + S3C24X0_REG8 EP_INT_EN_REG; + S3C24X0_REG8 res5[15]; + S3C24X0_REG8 USB_INT_EN_REG; + S3C24X0_REG8 res6[3]; + S3C24X0_REG8 FRAME_NUM1_REG; + S3C24X0_REG8 res7[3]; + S3C24X0_REG8 FRAME_NUM2_REG; + S3C24X0_REG8 res8[3]; + S3C24X0_REG8 INDEX_REG; + S3C24X0_REG8 res9[7]; + S3C24X0_REG8 MAXP_REG; + S3C24X0_REG8 res10[7]; + S3C24X0_REG8 EP0_CSR_IN_CSR1_REG; + S3C24X0_REG8 res11[3]; + S3C24X0_REG8 IN_CSR2_REG; + S3C24X0_REG8 res12[3]; + S3C24X0_REG8 OUT_CSR1_REG; + S3C24X0_REG8 res13[7]; + S3C24X0_REG8 OUT_CSR2_REG; + S3C24X0_REG8 res14[3]; + S3C24X0_REG8 OUT_FIFO_CNT1_REG; + S3C24X0_REG8 res15[3]; + S3C24X0_REG8 OUT_FIFO_CNT2_REG; + S3C24X0_REG8 res16[3]; +#endif /* __BIG_ENDIAN */ + S3C24X0_USB_DEV_FIFOS fifo[5]; + S3C24X0_USB_DEV_DMAS dma[5]; +} /*__attribute__((__packed__))*/ S3C24X0_USB_DEVICE; + +/* WATCH DOG TIMER (see manual chapter 18) */ +typedef struct +{ + S3C24X0_REG32 WTCON; + S3C24X0_REG32 WTDAT; + S3C24X0_REG32 WTCNT; +} /*__attribute__((__packed__))*/ S3C24X0_WATCHDOG; + +/* IIC (see manual chapter 20) */ +typedef struct +{ + S3C24X0_REG32 IICCON; + S3C24X0_REG32 IICSTAT; + S3C24X0_REG32 IICADD; + S3C24X0_REG32 IICDS; +} /*__attribute__((__packed__))*/ S3C24X0_I2C; + +/* IIS (see manual chapter 21) */ +typedef struct +{ +#ifdef __BIG_ENDIAN + S3C24X0_REG16 res1; + S3C24X0_REG16 IISCON; + S3C24X0_REG16 res2; + S3C24X0_REG16 IISMOD; + S3C24X0_REG16 res3; + S3C24X0_REG16 IISPSR; + S3C24X0_REG16 res4; + S3C24X0_REG16 IISFCON; + S3C24X0_REG16 res5; + S3C24X0_REG16 IISFIFO; +#else /* little endian */ + S3C24X0_REG16 IISCON; + S3C24X0_REG16 res1; + S3C24X0_REG16 IISMOD; + S3C24X0_REG16 res2; + S3C24X0_REG16 IISPSR; + S3C24X0_REG16 res3; + S3C24X0_REG16 IISFCON; + S3C24X0_REG16 res4; + S3C24X0_REG16 IISFIFO; + S3C24X0_REG16 res5; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_I2S; + +/* I/O PORT (see manual chapter 9) */ +typedef struct +{ +#ifdef CONFIG_S3C2400 + S3C24X0_REG32 PACON; + S3C24X0_REG32 PADAT; + + S3C24X0_REG32 PBCON; + S3C24X0_REG32 PBDAT; + S3C24X0_REG32 PBUP; + + S3C24X0_REG32 PCCON; + S3C24X0_REG32 PCDAT; + S3C24X0_REG32 PCUP; + + S3C24X0_REG32 PDCON; + S3C24X0_REG32 PDDAT; + S3C24X0_REG32 PDUP; + + S3C24X0_REG32 PECON; + S3C24X0_REG32 PEDAT; + S3C24X0_REG32 PEUP; + + S3C24X0_REG32 PFCON; + S3C24X0_REG32 PFDAT; + S3C24X0_REG32 PFUP; + + S3C24X0_REG32 PGCON; + S3C24X0_REG32 PGDAT; + S3C24X0_REG32 PGUP; + + S3C24X0_REG32 OPENCR; + + S3C24X0_REG32 MISCCR; + S3C24X0_REG32 EXTINT; +#endif +#ifdef CONFIG_S3C2410 + S3C24X0_REG32 GPACON; + S3C24X0_REG32 GPADAT; + S3C24X0_REG32 res1[2]; + S3C24X0_REG32 GPBCON; + S3C24X0_REG32 GPBDAT; + S3C24X0_REG32 GPBUP; + S3C24X0_REG32 res2; + S3C24X0_REG32 GPCCON; + S3C24X0_REG32 GPCDAT; + S3C24X0_REG32 GPCUP; + S3C24X0_REG32 res3; + S3C24X0_REG32 GPDCON; + S3C24X0_REG32 GPDDAT; + S3C24X0_REG32 GPDUP; + S3C24X0_REG32 res4; + S3C24X0_REG32 GPECON; + S3C24X0_REG32 GPEDAT; + S3C24X0_REG32 GPEUP; + S3C24X0_REG32 res5; + S3C24X0_REG32 GPFCON; + S3C24X0_REG32 GPFDAT; + S3C24X0_REG32 GPFUP; + S3C24X0_REG32 res6; + S3C24X0_REG32 GPGCON; + S3C24X0_REG32 GPGDAT; + S3C24X0_REG32 GPGUP; + S3C24X0_REG32 res7; + S3C24X0_REG32 GPHCON; + S3C24X0_REG32 GPHDAT; + S3C24X0_REG32 GPHUP; + S3C24X0_REG32 res8; + + S3C24X0_REG32 MISCCR; + S3C24X0_REG32 DCLKCON; + S3C24X0_REG32 EXTINT0; + S3C24X0_REG32 EXTINT1; + S3C24X0_REG32 EXTINT2; + S3C24X0_REG32 EINTFLT0; + S3C24X0_REG32 EINTFLT1; + S3C24X0_REG32 EINTFLT2; + S3C24X0_REG32 EINTFLT3; + S3C24X0_REG32 EINTMASK; + S3C24X0_REG32 EINTPEND; + S3C24X0_REG32 GSTATUS0; + S3C24X0_REG32 GSTATUS1; + S3C24X0_REG32 GSTATUS2; + S3C24X0_REG32 GSTATUS3; + S3C24X0_REG32 GSTATUS4; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_GPIO; + +/* RTC (see manual chapter 17) */ +typedef struct +{ +#ifdef __BIG_ENDIAN + S3C24X0_REG8 res1[67]; + S3C24X0_REG8 RTCCON; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 TICNT; + S3C24X0_REG8 res3[11]; + S3C24X0_REG8 RTCALM; + S3C24X0_REG8 res4[3]; + S3C24X0_REG8 ALMSEC; + S3C24X0_REG8 res5[3]; + S3C24X0_REG8 ALMMIN; + S3C24X0_REG8 res6[3]; + S3C24X0_REG8 ALMHOUR; + S3C24X0_REG8 res7[3]; + S3C24X0_REG8 ALMDATE; + S3C24X0_REG8 res8[3]; + S3C24X0_REG8 ALMMON; + S3C24X0_REG8 res9[3]; + S3C24X0_REG8 ALMYEAR; + S3C24X0_REG8 res10[3]; + S3C24X0_REG8 RTCRST; + S3C24X0_REG8 res11[3]; + S3C24X0_REG8 BCDSEC; + S3C24X0_REG8 res12[3]; + S3C24X0_REG8 BCDMIN; + S3C24X0_REG8 res13[3]; + S3C24X0_REG8 BCDHOUR; + S3C24X0_REG8 res14[3]; + S3C24X0_REG8 BCDDATE; + S3C24X0_REG8 res15[3]; + S3C24X0_REG8 BCDDAY; + S3C24X0_REG8 res16[3]; + S3C24X0_REG8 BCDMON; + S3C24X0_REG8 res17[3]; + S3C24X0_REG8 BCDYEAR; +#else /* little endian */ + S3C24X0_REG8 res0[64]; + S3C24X0_REG8 RTCCON; + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 TICNT; + S3C24X0_REG8 res2[11]; + S3C24X0_REG8 RTCALM; + S3C24X0_REG8 res3[3]; + S3C24X0_REG8 ALMSEC; + S3C24X0_REG8 res4[3]; + S3C24X0_REG8 ALMMIN; + S3C24X0_REG8 res5[3]; + S3C24X0_REG8 ALMHOUR; + S3C24X0_REG8 res6[3]; + S3C24X0_REG8 ALMDATE; + S3C24X0_REG8 res7[3]; + S3C24X0_REG8 ALMMON; + S3C24X0_REG8 res8[3]; + S3C24X0_REG8 ALMYEAR; + S3C24X0_REG8 res9[3]; + S3C24X0_REG8 RTCRST; + S3C24X0_REG8 res10[3]; + S3C24X0_REG8 BCDSEC; + S3C24X0_REG8 res11[3]; + S3C24X0_REG8 BCDMIN; + S3C24X0_REG8 res12[3]; + S3C24X0_REG8 BCDHOUR; + S3C24X0_REG8 res13[3]; + S3C24X0_REG8 BCDDATE; + S3C24X0_REG8 res14[3]; + S3C24X0_REG8 BCDDAY; + S3C24X0_REG8 res15[3]; + S3C24X0_REG8 BCDMON; + S3C24X0_REG8 res16[3]; + S3C24X0_REG8 BCDYEAR; + S3C24X0_REG8 res17[3]; +#endif +} /*__attribute__((__packed__))*/ S3C24X0_RTC; + +/* ADC (see manual chapter 16) */ +typedef struct +{ + S3C24X0_REG32 ADCCON; + S3C24X0_REG32 ADCDAT; +} /*__attribute__((__packed__))*/ S3C2400_ADC; + +/* ADC (see manual chapter 16) */ +typedef struct +{ + S3C24X0_REG32 ADCCON; + S3C24X0_REG32 ADCTSC; + S3C24X0_REG32 ADCDLY; + S3C24X0_REG32 ADCDAT0; + S3C24X0_REG32 ADCDAT1; +} /*__attribute__((__packed__))*/ S3C2410_ADC; + +/* SPI (see manual chapter 22) */ +typedef struct +{ + S3C24X0_REG32 SPCON; + S3C24X0_REG32 SPSTA; + S3C24X0_REG32 SPPIN; + S3C24X0_REG32 SPPRE; + S3C24X0_REG32 SPTDAT; + S3C24X0_REG32 SPRDAT; + S3C24X0_REG32 res[2]; +} __attribute__ ((__packed__)) S3C24X0_SPI_CHANNEL; + +typedef struct +{ + S3C24X0_SPI_CHANNEL ch[S3C24X0_SPI_CHANNELS]; +} /*__attribute__((__packed__))*/ S3C24X0_SPI; + +/* MMC INTERFACE (see S3C2400 manual chapter 19) */ +typedef struct +{ +#ifdef __BIG_ENDIAN + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 MMCON; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 MMCRR; + S3C24X0_REG8 res3[3]; + S3C24X0_REG8 MMFCON; + S3C24X0_REG8 res4[3]; + S3C24X0_REG8 MMSTA; + S3C24X0_REG16 res5; + S3C24X0_REG16 MMFSTA; + S3C24X0_REG8 res6[3]; + S3C24X0_REG8 MMPRE; + S3C24X0_REG16 res7; + S3C24X0_REG16 MMLEN; + S3C24X0_REG8 res8[3]; + S3C24X0_REG8 MMCR7; + S3C24X0_REG32 MMRSP[4]; + S3C24X0_REG8 res9[3]; + S3C24X0_REG8 MMCMD0; + S3C24X0_REG32 MMCMD1; + S3C24X0_REG16 res10; + S3C24X0_REG16 MMCR16; + S3C24X0_REG8 res11[3]; + S3C24X0_REG8 MMDAT; +#else + S3C24X0_REG8 MMCON; + S3C24X0_REG8 res1[3]; + S3C24X0_REG8 MMCRR; + S3C24X0_REG8 res2[3]; + S3C24X0_REG8 MMFCON; + S3C24X0_REG8 res3[3]; + S3C24X0_REG8 MMSTA; + S3C24X0_REG8 res4[3]; + S3C24X0_REG16 MMFSTA; + S3C24X0_REG16 res5; + S3C24X0_REG8 MMPRE; + S3C24X0_REG8 res6[3]; + S3C24X0_REG16 MMLEN; + S3C24X0_REG16 res7; + S3C24X0_REG8 MMCR7; + S3C24X0_REG8 res8[3]; + S3C24X0_REG32 MMRSP[4]; + S3C24X0_REG8 MMCMD0; + S3C24X0_REG8 res9[3]; + S3C24X0_REG32 MMCMD1; + S3C24X0_REG16 MMCR16; + S3C24X0_REG16 res10; + S3C24X0_REG8 MMDAT; + S3C24X0_REG8 res11[3]; +#endif +} /*__attribute__((__packed__))*/ S3C2400_MMC; + +/* SD INTERFACE (see S3C2410 manual chapter 19) */ +typedef struct +{ + S3C24X0_REG32 SDICON; + S3C24X0_REG32 SDIPRE; + S3C24X0_REG32 SDICARG; + S3C24X0_REG32 SDICCON; + S3C24X0_REG32 SDICSTA; + S3C24X0_REG32 SDIRSP0; + S3C24X0_REG32 SDIRSP1; + S3C24X0_REG32 SDIRSP2; + S3C24X0_REG32 SDIRSP3; + S3C24X0_REG32 SDIDTIMER; + S3C24X0_REG32 SDIBSIZE; + S3C24X0_REG32 SDIDCON; + S3C24X0_REG32 SDIDCNT; + S3C24X0_REG32 SDIDSTA; + S3C24X0_REG32 SDIFSTA; +#ifdef __BIG_ENDIAN + S3C24X0_REG8 res[3]; + S3C24X0_REG8 SDIDAT; +#else + S3C24X0_REG8 SDIDAT; + S3C24X0_REG8 res[3]; +#endif + S3C24X0_REG32 SDIIMSK; +} /*__attribute__((__packed__))*/ S3C2410_SDI; + +#if 0 +/* Memory control */ +#define rBWSCON (*(volatile unsigned *)0x48000000) +#define rBANKCON0 (*(volatile unsigned *)0x48000004) +#define rBANKCON1 (*(volatile unsigned *)0x48000008) +#define rBANKCON2 (*(volatile unsigned *)0x4800000C) +#define rBANKCON3 (*(volatile unsigned *)0x48000010) +#define rBANKCON4 (*(volatile unsigned *)0x48000014) +#define rBANKCON5 (*(volatile unsigned *)0x48000018) +#define rBANKCON6 (*(volatile unsigned *)0x4800001C) +#define rBANKCON7 (*(volatile unsigned *)0x48000020) +#define rREFRESH (*(volatile unsigned *)0x48000024) +#define rBANKSIZE (*(volatile unsigned *)0x48000028) +#define rMRSRB6 (*(volatile unsigned *)0x4800002C) +#define rMRSRB7 (*(volatile unsigned *)0x48000030) + +/* USB HOST */ +#define rHcRevision (*(volatile unsigned *)0x49000000) +#define rHcControl (*(volatile unsigned *)0x49000004) +#define rHcCommonStatus (*(volatile unsigned *)0x49000008) +#define rHcInterruptStatus (*(volatile unsigned *)0x4900000C) +#define rHcInterruptEnable (*(volatile unsigned *)0x49000010) +#define rHcInterruptDisable (*(volatile unsigned *)0x49000014) +#define rHcHCCA (*(volatile unsigned *)0x49000018) +#define rHcPeriodCuttendED (*(volatile unsigned *)0x4900001C) +#define rHcControlHeadED (*(volatile unsigned *)0x49000020) +#define rHcControlCurrentED (*(volatile unsigned *)0x49000024) +#define rHcBulkHeadED (*(volatile unsigned *)0x49000028) +#define rHcBuldCurrentED (*(volatile unsigned *)0x4900002C) +#define rHcDoneHead (*(volatile unsigned *)0x49000030) +#define rHcRmInterval (*(volatile unsigned *)0x49000034) +#define rHcFmRemaining (*(volatile unsigned *)0x49000038) +#define rHcFmNumber (*(volatile unsigned *)0x4900003C) +#define rHcPeriodicStart (*(volatile unsigned *)0x49000040) +#define rHcLSThreshold (*(volatile unsigned *)0x49000044) +#define rHcRhDescriptorA (*(volatile unsigned *)0x49000048) +#define rHcRhDescriptorB (*(volatile unsigned *)0x4900004C) +#define rHcRhStatus (*(volatile unsigned *)0x49000050) +#define rHcRhPortStatus1 (*(volatile unsigned *)0x49000054) +#define rHcRhPortStatus2 (*(volatile unsigned *)0x49000058) + +/* INTERRUPT */ +#define rSRCPND (*(volatile unsigned *)0x4A000000) +#define rINTMOD (*(volatile unsigned *)0x4A000004) +#define rINTMSK (*(volatile unsigned *)0x4A000008) +#define rPRIORITY (*(volatile unsigned *)0x4A00000C) +#define rINTPND (*(volatile unsigned *)0x4A000010) +#define rINTOFFSET (*(volatile unsigned *)0x4A000014) +#define rSUBSRCPND (*(volatile unsigned *)0x4A000018) +#define rINTSUBMSK (*(volatile unsigned *)0x4A00001C) + +/* DMA */ +#define rDISRC0 (*(volatile unsigned *)0x4B000000) +#define rDISRCC0 (*(volatile unsigned *)0x4B000004) +#define rDIDST0 (*(volatile unsigned *)0x4B000008) +#define rDIDSTC0 (*(volatile unsigned *)0x4B00000C) +#define rDCON0 (*(volatile unsigned *)0x4B000010) +#define rDSTAT0 (*(volatile unsigned *)0x4B000014) +#define rDCSRC0 (*(volatile unsigned *)0x4B000018) +#define rDCDST0 (*(volatile unsigned *)0x4B00001C) +#define rDMASKTRIG0 (*(volatile unsigned *)0x4B000020) +#define rDISRC1 (*(volatile unsigned *)0x4B000040) +#define rDISRCC1 (*(volatile unsigned *)0x4B000044) +#define rDIDST1 (*(volatile unsigned *)0x4B000048) +#define rDIDSTC1 (*(volatile unsigned *)0x4B00004C) +#define rDCON1 (*(volatile unsigned *)0x4B000050) +#define rDSTAT1 (*(volatile unsigned *)0x4B000054) +#define rDCSRC1 (*(volatile unsigned *)0x4B000058) +#define rDCDST1 (*(volatile unsigned *)0x4B00005C) +#define rDMASKTRIG1 (*(volatile unsigned *)0x4B000060) +#define rDISRC2 (*(volatile unsigned *)0x4B000080) +#define rDISRCC2 (*(volatile unsigned *)0x4B000084) +#define rDIDST2 (*(volatile unsigned *)0x4B000088) +#define rDIDSTC2 (*(volatile unsigned *)0x4B00008C) +#define rDCON2 (*(volatile unsigned *)0x4B000090) +#define rDSTAT2 (*(volatile unsigned *)0x4B000094) +#define rDCSRC2 (*(volatile unsigned *)0x4B000098) +#define rDCDST2 (*(volatile unsigned *)0x4B00009C) +#define rDMASKTRIG2 (*(volatile unsigned *)0x4B0000A0) +#define rDISRC3 (*(volatile unsigned *)0x4B0000C0) +#define rDISRCC3 (*(volatile unsigned *)0x4B0000C4) +#define rDIDST3 (*(volatile unsigned *)0x4B0000C8) +#define rDIDSTC3 (*(volatile unsigned *)0x4B0000CC) +#define rDCON3 (*(volatile unsigned *)0x4B0000D0) +#define rDSTAT3 (*(volatile unsigned *)0x4B0000D4) +#define rDCSRC3 (*(volatile unsigned *)0x4B0000D8) +#define rDCDST3 (*(volatile unsigned *)0x4B0000DC) +#define rDMASKTRIG3 (*(volatile unsigned *)0x4B0000E0) + +/* CLOCK & POWER MANAGEMENT */ +#define rLOCKTIME (*(volatile unsigned *)0x4C000000) +#define rMPLLCON (*(volatile unsigned *)0x4C000004) +#define rUPLLCON (*(volatile unsigned *)0x4C000008) +#define rCLKCON (*(volatile unsigned *)0x4C00000C) +#define rCLKSLOW (*(volatile unsigned *)0x4C000010) +#define rCLKDIVN (*(volatile unsigned *)0x4C000014) + +/* LCD CONTROLLER */ +#define rLCDCON1 (*(volatile unsigned *)0x4D000000) +#define rLCDCON2 (*(volatile unsigned *)0x4D000004) +#define rLCDCON3 (*(volatile unsigned *)0x4D000008) +#define rLCDCON4 (*(volatile unsigned *)0x4D00000C) +#define rLCDCON5 (*(volatile unsigned *)0x4D000010) +#define rLCDSADDR1 (*(volatile unsigned *)0x4D000014) +#define rLCDSADDR2 (*(volatile unsigned *)0x4D000018) +#define rLCDSADDR3 (*(volatile unsigned *)0x4D00001C) +#define rREDLUT (*(volatile unsigned *)0x4D000020) +#define rGREENLUT (*(volatile unsigned *)0x4D000024) +#define rBLUELUT (*(volatile unsigned *)0x4D000028) +#define rDITHMODE (*(volatile unsigned *)0x4D00004C) +#define rTPAL (*(volatile unsigned *)0x4D000050) +#define rLCDINTPND (*(volatile unsigned *)0x4D000054) +#define rLCDSRCPND (*(volatile unsigned *)0x4D000058) +#define rLCDINTMSK (*(volatile unsigned *)0x4D00005C) + +/* NAND FLASH */ +#define rNFCONF (*(volatile unsigned *)0x4E000000) +#define rNFCMD (*(volatile unsigned *)0x4E000004) +#define rNFADDR (*(volatile unsigned *)0x4E000008) +#define rNFDATA (*(volatile unsigned *)0x4E00000C) +#define rNFSTAT (*(volatile unsigned *)0x4E000010) +#define rNFECC (*(volatile unsigned *)0x4E000014) + +/* UART */ +#define rULCON0 (*(volatile unsigned *)0x50000000) +#define rUCON0 (*(volatile unsigned *)0x50000004) +#define rUFCON0 (*(volatile unsigned *)0x50000008) +#define rUMCON0 (*(volatile unsigned *)0x5000000C) +#define rUTRSTAT0 (*(volatile unsigned *)0x50000010) +#define rUERSTAT0 (*(volatile unsigned *)0x50000014) +#define rUFSTAT0 (*(volatile unsigned *)0x50000018) +#define rUMSTAT0 (*(volatile unsigned *)0x5000001C) +#define rUBRDIV0 (*(volatile unsigned *)0x50000028) + +#define rULCON1 (*(volatile unsigned *)0x50004000) +#define rUCON1 (*(volatile unsigned *)0x50004004) +#define rUFCON1 (*(volatile unsigned *)0x50004008) +#define rUMCON1 (*(volatile unsigned *)0x5000400C) +#define rUTRSTAT1 (*(volatile unsigned *)0x50004010) +#define rUERSTAT1 (*(volatile unsigned *)0x50004014) +#define rUFSTAT1 (*(volatile unsigned *)0x50004018) +#define rUMSTAT1 (*(volatile unsigned *)0x5000401C) +#define rUBRDIV1 (*(volatile unsigned *)0x50004028) + +#define rULCON2 (*(volatile unsigned *)0x50008000) +#define rUCON2 (*(volatile unsigned *)0x50008004) +#define rUFCON2 (*(volatile unsigned *)0x50008008) +#define rUTRSTAT2 (*(volatile unsigned *)0x50008010) +#define rUERSTAT2 (*(volatile unsigned *)0x50008014) +#define rUFSTAT2 (*(volatile unsigned *)0x50008018) +#define rUBRDIV2 (*(volatile unsigned *)0x50008028) + +#ifdef __BIG_ENDIAN +#define rUTXH0 (*(volatile unsigned char *)0x50000023) +#define rURXH0 (*(volatile unsigned char *)0x50000027) +#define rUTXH1 (*(volatile unsigned char *)0x50004023) +#define rURXH1 (*(volatile unsigned char *)0x50004027) +#define rUTXH2 (*(volatile unsigned char *)0x50008023) +#define rURXH2 (*(volatile unsigned char *)0x50008027) + +#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000023)=(unsigned char)(ch) +#define RdURXH0() (*(volatile unsigned char *)0x50000027) +#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004023)=(unsigned char)(ch) +#define RdURXH1() (*(volatile unsigned char *)0x50004027) +#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008023)=(unsigned char)(ch) +#define RdURXH2() (*(volatile unsigned char *)0x50008027) + +#define UTXH0 (0x50000020+3) /* byte_access address by DMA */ +#define URXH0 (0x50000024+3) +#define UTXH1 (0x50004020+3) +#define URXH1 (0x50004024+3) +#define UTXH2 (0x50008020+3) +#define URXH2 (0x50008024+3) + +#else /* Little Endian */ +#define rUTXH0 (*(volatile unsigned char *)0x50000020) +#define rURXH0 (*(volatile unsigned char *)0x50000024) +#define rUTXH1 (*(volatile unsigned char *)0x50004020) +#define rURXH1 (*(volatile unsigned char *)0x50004024) +#define rUTXH2 (*(volatile unsigned char *)0x50008020) +#define rURXH2 (*(volatile unsigned char *)0x50008024) + +#define WrUTXH0(ch) (*(volatile unsigned char *)0x50000020)=(unsigned char)(ch) +#define RdURXH0() (*(volatile unsigned char *)0x50000024) +#define WrUTXH1(ch) (*(volatile unsigned char *)0x50004020)=(unsigned char)(ch) +#define RdURXH1() (*(volatile unsigned char *)0x50004024) +#define WrUTXH2(ch) (*(volatile unsigned char *)0x50008020)=(unsigned char)(ch) +#define RdURXH2() (*(volatile unsigned char *)0x50008024) + +#define UTXH0 (0x50000020) /* byte_access address by DMA */ +#define URXH0 (0x50000024) +#define UTXH1 (0x50004020) +#define URXH1 (0x50004024) +#define UTXH2 (0x50008020) +#define URXH2 (0x50008024) +#endif + +/* PWM TIMER */ +#define rTCFG0 (*(volatile unsigned *)0x51000000) +#define rTCFG1 (*(volatile unsigned *)0x51000004) +#define rTCON (*(volatile unsigned *)0x51000008) +#define rTCNTB0 (*(volatile unsigned *)0x5100000C) +#define rTCMPB0 (*(volatile unsigned *)0x51000010) +#define rTCNTO0 (*(volatile unsigned *)0x51000014) +#define rTCNTB1 (*(volatile unsigned *)0x51000018) +#define rTCMPB1 (*(volatile unsigned *)0x5100001C) +#define rTCNTO1 (*(volatile unsigned *)0x51000020) +#define rTCNTB2 (*(volatile unsigned *)0x51000024) +#define rTCMPB2 (*(volatile unsigned *)0x51000028) +#define rTCNTO2 (*(volatile unsigned *)0x5100002C) +#define rTCNTB3 (*(volatile unsigned *)0x51000030) +#define rTCMPB3 (*(volatile unsigned *)0x51000034) +#define rTCNTO3 (*(volatile unsigned *)0x51000038) +#define rTCNTB4 (*(volatile unsigned *)0x5100003C) +#define rTCNTO4 (*(volatile unsigned *)0x51000040) + +/* USB DEVICE */ +#ifdef __BIG_ENDIAN +#define rFUNC_ADDR_REG (*(volatile unsigned char *)0x52000143) +#define rPWR_REG (*(volatile unsigned char *)0x52000147) +#define rEP_INT_REG (*(volatile unsigned char *)0x5200014B) +#define rUSB_INT_REG (*(volatile unsigned char *)0x5200015B) +#define rEP_INT_EN_REG (*(volatile unsigned char *)0x5200015F) +#define rUSB_INT_EN_REG (*(volatile unsigned char *)0x5200016F) +#define rFRAME_NUM1_REG (*(volatile unsigned char *)0x52000173) +#define rFRAME_NUM2_REG (*(volatile unsigned char *)0x52000177) +#define rINDEX_REG (*(volatile unsigned char *)0x5200017B) +#define rMAXP_REG (*(volatile unsigned char *)0x52000183) +#define rEP0_CSR (*(volatile unsigned char *)0x52000187) +#define rIN_CSR1_REG (*(volatile unsigned char *)0x52000187) +#define rIN_CSR2_REG (*(volatile unsigned char *)0x5200018B) +#define rOUT_CSR1_REG (*(volatile unsigned char *)0x52000193) +#define rOUT_CSR2_REG (*(volatile unsigned char *)0x52000197) +#define rOUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x5200019B) +#define rOUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019F) +#define rEP0_FIFO (*(volatile unsigned char *)0x520001C3) +#define rEP1_FIFO (*(volatile unsigned char *)0x520001C7) +#define rEP2_FIFO (*(volatile unsigned char *)0x520001CB) +#define rEP3_FIFO (*(volatile unsigned char *)0x520001CF) +#define rEP4_FIFO (*(volatile unsigned char *)0x520001D3) +#define rEP1_DMA_CON (*(volatile unsigned char *)0x52000203) +#define rEP1_DMA_UNIT (*(volatile unsigned char *)0x52000207) +#define rEP1_DMA_FIFO (*(volatile unsigned char *)0x5200020B) +#define rEP1_DMA_TX_LO (*(volatile unsigned char *)0x5200020F) +#define rEP1_DMA_TX_MD (*(volatile unsigned char *)0x52000213) +#define rEP1_DMA_TX_HI (*(volatile unsigned char *)0x52000217) +#define rEP2_DMA_CON (*(volatile unsigned char *)0x5200021B) +#define rEP2_DMA_UNIT (*(volatile unsigned char *)0x5200021F) +#define rEP2_DMA_FIFO (*(volatile unsigned char *)0x52000223) +#define rEP2_DMA_TX_LO (*(volatile unsigned char *)0x52000227) +#define rEP2_DMA_TX_MD (*(volatile unsigned char *)0x5200022B) +#define rEP2_DMA_TX_HI (*(volatile unsigned char *)0x5200022F) +#define rEP3_DMA_CON (*(volatile unsigned char *)0x52000243) +#define rEP3_DMA_UNIT (*(volatile unsigned char *)0x52000247) +#define rEP3_DMA_FIFO (*(volatile unsigned char *)0x5200024B) +#define rEP3_DMA_TX_LO (*(volatile unsigned char *)0x5200024F) +#define rEP3_DMA_TX_MD (*(volatile unsigned char *)0x52000253) +#define rEP3_DMA_TX_HI (*(volatile unsigned char *)0x52000257) +#define rEP4_DMA_CON (*(volatile unsigned char *)0x5200025B) +#define rEP4_DMA_UNIT (*(volatile unsigned char *)0x5200025F) +#define rEP4_DMA_FIFO (*(volatile unsigned char *)0x52000263) +#define rEP4_DMA_TX_LO (*(volatile unsigned char *)0x52000267) +#define rEP4_DMA_TX_MD (*(volatile unsigned char *)0x5200026B) +#define rEP4_DMA_TX_HI (*(volatile unsigned char *)0x5200026F) +#else /* little endian */ +#define rFUNC_ADDR_REG (*(volatile unsigned char *)0x52000140) +#define rPWR_REG (*(volatile unsigned char *)0x52000144) +#define rEP_INT_REG (*(volatile unsigned char *)0x52000148) +#define rUSB_INT_REG (*(volatile unsigned char *)0x52000158) +#define rEP_INT_EN_REG (*(volatile unsigned char *)0x5200015C) +#define rUSB_INT_EN_REG (*(volatile unsigned char *)0x5200016C) +#define rFRAME_NUM1_REG (*(volatile unsigned char *)0x52000170) +#define rFRAME_NUM2_REG (*(volatile unsigned char *)0x52000174) +#define rINDEX_REG (*(volatile unsigned char *)0x52000178) +#define rMAXP_REG (*(volatile unsigned char *)0x52000180) +#define rEP0_CSR (*(volatile unsigned char *)0x52000184) +#define rIN_CSR1_REG (*(volatile unsigned char *)0x52000184) +#define rIN_CSR2_REG (*(volatile unsigned char *)0x52000188) +#define rOUT_CSR1_REG (*(volatile unsigned char *)0x52000190) +#define rOUT_CSR2_REG (*(volatile unsigned char *)0x52000194) +#define rOUT_FIFO_CNT1_REG (*(volatile unsigned char *)0x52000198) +#define rOUT_FIFO_CNT2_REG (*(volatile unsigned char *)0x5200019C) +#define rEP0_FIFO (*(volatile unsigned char *)0x520001C0) +#define rEP1_FIFO (*(volatile unsigned char *)0x520001C4) +#define rEP2_FIFO (*(volatile unsigned char *)0x520001C8) +#define rEP3_FIFO (*(volatile unsigned char *)0x520001CC) +#define rEP4_FIFO (*(volatile unsigned char *)0x520001D0) +#define rEP1_DMA_CON (*(volatile unsigned char *)0x52000200) +#define rEP1_DMA_UNIT (*(volatile unsigned char *)0x52000204) +#define rEP1_DMA_FIFO (*(volatile unsigned char *)0x52000208) +#define rEP1_DMA_TX_LO (*(volatile unsigned char *)0x5200020C) +#define rEP1_DMA_TX_MD (*(volatile unsigned char *)0x52000210) +#define rEP1_DMA_TX_HI (*(volatile unsigned char *)0x52000214) +#define rEP2_DMA_CON (*(volatile unsigned char *)0x52000218) +#define rEP2_DMA_UNIT (*(volatile unsigned char *)0x5200021C) +#define rEP2_DMA_FIFO (*(volatile unsigned char *)0x52000220) +#define rEP2_DMA_TX_LO (*(volatile unsigned char *)0x52000224) +#define rEP2_DMA_TX_MD (*(volatile unsigned char *)0x52000228) +#define rEP2_DMA_TX_HI (*(volatile unsigned char *)0x5200022C) +#define rEP3_DMA_CON (*(volatile unsigned char *)0x52000240) +#define rEP3_DMA_UNIT (*(volatile unsigned char *)0x52000244) +#define rEP3_DMA_FIFO (*(volatile unsigned char *)0x52000248) +#define rEP3_DMA_TX_LO (*(volatile unsigned char *)0x5200024C) +#define rEP3_DMA_TX_MD (*(volatile unsigned char *)0x52000250) +#define rEP3_DMA_TX_HI (*(volatile unsigned char *)0x52000254) +#define rEP4_DMA_CON (*(volatile unsigned char *)0x52000258) +#define rEP4_DMA_UNIT (*(volatile unsigned char *)0x5200025C) +#define rEP4_DMA_FIFO (*(volatile unsigned char *)0x52000260) +#define rEP4_DMA_TX_LO (*(volatile unsigned char *)0x52000264) +#define rEP4_DMA_TX_MD (*(volatile unsigned char *)0x52000268) +#define rEP4_DMA_TX_HI (*(volatile unsigned char *)0x5200026C) +#endif /* __BIG_ENDIAN */ + +/* WATCH DOG TIMER */ +#define rWTCON (*(volatile unsigned *)0x53000000) +#define rWTDAT (*(volatile unsigned *)0x53000004) +#define rWTCNT (*(volatile unsigned *)0x53000008) + +/* IIC */ +#define rIICCON (*(volatile unsigned *)0x54000000) +#define rIICSTAT (*(volatile unsigned *)0x54000004) +#define rIICADD (*(volatile unsigned *)0x54000008) +#define rIICDS (*(volatile unsigned *)0x5400000C) + +/* IIS */ +#define rIISCON (*(volatile unsigned *)0x55000000) +#define rIISMOD (*(volatile unsigned *)0x55000004) +#define rIISPSR (*(volatile unsigned *)0x55000008) +#define rIISFCON (*(volatile unsigned *)0x5500000C) + +#ifdef __BIG_ENDIAN +#define IISFIF ((volatile unsigned short *)0x55000012) +#else /* little endian */ +#define IISFIF ((volatile unsigned short *)0x55000010) +#endif + +/* I/O PORT */ +#define rGPACON (*(volatile unsigned *)0x56000000) +#define rGPADAT (*(volatile unsigned *)0x56000004) + +#define rGPBCON (*(volatile unsigned *)0x56000010) +#define rGPBDAT (*(volatile unsigned *)0x56000014) +#define rGPBUP (*(volatile unsigned *)0x56000018) + +#define rGPCCON (*(volatile unsigned *)0x56000020) +#define rGPCDAT (*(volatile unsigned *)0x56000024) +#define rGPCUP (*(volatile unsigned *)0x56000028) + +#define rGPDCON (*(volatile unsigned *)0x56000030) +#define rGPDDAT (*(volatile unsigned *)0x56000034) +#define rGPDUP (*(volatile unsigned *)0x56000038) + +#define rGPECON (*(volatile unsigned *)0x56000040) +#define rGPEDAT (*(volatile unsigned *)0x56000044) +#define rGPEUP (*(volatile unsigned *)0x56000048) + +#define rGPFCON (*(volatile unsigned *)0x56000050) +#define rGPFDAT (*(volatile unsigned *)0x56000054) +#define rGPFUP (*(volatile unsigned *)0x56000058) + +#define rGPGCON (*(volatile unsigned *)0x56000060) +#define rGPGDAT (*(volatile unsigned *)0x56000064) +#define rGPGUP (*(volatile unsigned *)0x56000068) + +#define rGPHCON (*(volatile unsigned *)0x56000070) +#define rGPHDAT (*(volatile unsigned *)0x56000074) +#define rGPHUP (*(volatile unsigned *)0x56000078) + +#define rMISCCR (*(volatile unsigned *)0x56000080) +#define rDCLKCON (*(volatile unsigned *)0x56000084) +#define rEXTINT0 (*(volatile unsigned *)0x56000088) +#define rEXTINT1 (*(volatile unsigned *)0x5600008C) +#define rEXTINT2 (*(volatile unsigned *)0x56000090) +#define rEINTFLT0 (*(volatile unsigned *)0x56000094) +#define rEINTFLT1 (*(volatile unsigned *)0x56000098) +#define rEINTFLT2 (*(volatile unsigned *)0x5600009C) +#define rEINTFLT3 (*(volatile unsigned *)0x560000A0) +#define rEINTMASK (*(volatile unsigned *)0x560000A4) +#define rEINTPEND (*(volatile unsigned *)0x560000A8) +#define rGSTATUS0 (*(volatile unsigned *)0x560000AC) +#define rGSTATUS1 (*(volatile unsigned *)0x560000B0) + +/* RTC */ +#ifdef __BIG_ENDIAN +#define rRTCCON (*(volatile unsigned char *)0x57000043) +#define rTICNT (*(volatile unsigned char *)0x57000047) +#define rRTCALM (*(volatile unsigned char *)0x57000053) +#define rALMSEC (*(volatile unsigned char *)0x57000057) +#define rALMMIN (*(volatile unsigned char *)0x5700005B) +#define rALMHOUR (*(volatile unsigned char *)0x5700005F) +#define rALMDATE (*(volatile unsigned char *)0x57000063) +#define rALMMON (*(volatile unsigned char *)0x57000067) +#define rALMYEAR (*(volatile unsigned char *)0x5700006B) +#define rRTCRST (*(volatile unsigned char *)0x5700006F) +#define rBCDSEC (*(volatile unsigned char *)0x57000073) +#define rBCDMIN (*(volatile unsigned char *)0x57000077) +#define rBCDHOUR (*(volatile unsigned char *)0x5700007B) +#define rBCDDATE (*(volatile unsigned char *)0x5700007F) +#define rBCDDAY (*(volatile unsigned char *)0x57000083) +#define rBCDMON (*(volatile unsigned char *)0x57000087) +#define rBCDYEAR (*(volatile unsigned char *)0x5700008B) +#else /* little endian */ +#define rRTCCON (*(volatile unsigned char *)0x57000040) +#define rTICNT (*(volatile unsigned char *)0x57000044) +#define rRTCALM (*(volatile unsigned char *)0x57000050) +#define rALMSEC (*(volatile unsigned char *)0x57000054) +#define rALMMIN (*(volatile unsigned char *)0x57000058) +#define rALMHOUR (*(volatile unsigned char *)0x5700005C) +#define rALMDATE (*(volatile unsigned char *)0x57000060) +#define rALMMON (*(volatile unsigned char *)0x57000064) +#define rALMYEAR (*(volatile unsigned char *)0x57000068) +#define rRTCRST (*(volatile unsigned char *)0x5700006C) +#define rBCDSEC (*(volatile unsigned char *)0x57000070) +#define rBCDMIN (*(volatile unsigned char *)0x57000074) +#define rBCDHOUR (*(volatile unsigned char *)0x57000078) +#define rBCDDATE (*(volatile unsigned char *)0x5700007C) +#define rBCDDAY (*(volatile unsigned char *)0x57000080) +#define rBCDMON (*(volatile unsigned char *)0x57000084) +#define rBCDYEAR (*(volatile unsigned char *)0x57000088) +#endif + +/* ADC */ +#define rADCCON (*(volatile unsigned *)0x58000000) +#define rADCTSC (*(volatile unsigned *)0x58000004) +#define rADCDLY (*(volatile unsigned *)0x58000008) +#define rADCDAT0 (*(volatile unsigned *)0x5800000C) +#define rADCDAT1 (*(volatile unsigned *)0x58000010) + +/* SPI */ +#define rSPCON0 (*(volatile unsigned *)0x59000000) +#define rSPSTA0 (*(volatile unsigned *)0x59000004) +#define rSPPIN0 (*(volatile unsigned *)0x59000008) +#define rSPPRE0 (*(volatile unsigned *)0x5900000C) +#define rSPTDAT0 (*(volatile unsigned *)0x59000010) +#define rSPRDAT0 (*(volatile unsigned *)0x59000014) +#define rSPCON1 (*(volatile unsigned *)0x59000020) +#define rSPSTA1 (*(volatile unsigned *)0x59000024) +#define rSPPIN1 (*(volatile unsigned *)0x59000028) +#define rSPPRE1 (*(volatile unsigned *)0x5900002C) +#define rSPTDAT1 (*(volatile unsigned *)0x59000030) +#define rSPRDAT1 (*(volatile unsigned *)0x59000034) + +/* SD INTERFACE */ +#define rSDICON (*(volatile unsigned *)0x5A000000) +#define rSDIPRE (*(volatile unsigned *)0x5A000004) +#define rSDICmdArg (*(volatile unsigned *)0x5A000008) +#define rSDICmdCon (*(volatile unsigned *)0x5A00000C) +#define rSDICmdSta (*(volatile unsigned *)0x5A000010) +#define rSDIRSP0 (*(volatile unsigned *)0x5A000014) +#define rSDIRSP1 (*(volatile unsigned *)0x5A000018) +#define rSDIRSP2 (*(volatile unsigned *)0x5A00001C) +#define rSDIRSP3 (*(volatile unsigned *)0x5A000020) +#define rSDIDTimer (*(volatile unsigned *)0x5A000024) +#define rSDIBSize (*(volatile unsigned *)0x5A000028) +#define rSDIDatCon (*(volatile unsigned *)0x5A00002C) +#define rSDIDatCnt (*(volatile unsigned *)0x5A000030) +#define rSDIDatSta (*(volatile unsigned *)0x5A000034) +#define rSDIFSTA (*(volatile unsigned *)0x5A000038) +#ifdef __BIG_ENDIAN +#define rSDIDAT (*(volatile unsigned char *)0x5A00003F) +#else +#define rSDIDAT (*(volatile unsigned char *)0x5A00003C) +#endif +#define rSDIIntMsk (*(volatile unsigned *)0x5A000040) + +#endif + +#endif /*__S3C24X0_H__*/ diff --git a/linux-bsp/asm-study/myboot/interrupt.c b/linux-bsp/asm-study/myboot/interrupt.c new file mode 100644 index 0000000..dbc9b7f --- /dev/null +++ b/linux-bsp/asm-study/myboot/interrupt.c @@ -0,0 +1,39 @@ +/******************************************************************************************** + * File: interrupt.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: The CPU interrupt vector table depends on function, called in start.S + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#include <common.h> + +void do_undefined_instruction(void) +{ + +} + +void do_software_interrupt(void) +{ +} + +void do_prefetch_abort(void) +{ +} + +void do_data_abort(void) +{ +} + +void do_not_used(void) +{ +} + +void do_irq(void) +{ +} + +void do_fiq(void) +{ +} diff --git a/linux-bsp/asm-study/myboot/k9f2g08.c b/linux-bsp/asm-study/myboot/k9f2g08.c new file mode 100644 index 0000000..b74813d --- /dev/null +++ b/linux-bsp/asm-study/myboot/k9f2g08.c @@ -0,0 +1,638 @@ +/******************************************************************************************** + * File: k9f2g08.c: K9F2G08 read/write/erase functions for bootstrap + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This C code is the first stage bootloader(named bootstrap) + main code, test on FL2440 board. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + + +/************************************************************* + * Read Status Register Definition of K9F2G08(Refer to k9f2g08u0m datasheet) + * + * |-------------------------------------------------------------------------------------| + * | I/O No. | Page Program | Block Erase | Cache Program | Read | Definition | + * |-------------------------------------------------------------------------------------| + * | I/O 0 | Pass/Fail | Pass/Fail | Pass/Fail(N) | Not use | Pass:0 Fail:1 | + * |-------------------------------------------------------------------------------------| + * | I/O 1 | Not use | Not use | Pass/Fail(N-1)| Not use | Pass:0 Fail:1 | + * |-------------------------------------------------------------------------------------| + * | I/O 2 | Not use | Not use | Not use | Not use | Don't care | + * |-------------------------------------------------------------------------------------| + * | I/O 3 | Not use | Not use | Not use | Not use | Don't care | + * |-------------------------------------------------------------------------------------| + * | I/O 4 | Not use | Not use | Not use | Not use | Don't care | + * |-------------------------------------------------------------------------------------| + * | I/O 5 | Ready/Busy | Ready/Busy |True Ready/Busy| Ready/Busy | Busy:0 Ready:1 | + * |-------------------------------------------------------------------------------------| + * | I/O 6 | Ready/Busy | Ready/Busy | Ready/Busy | Ready/Busy | Busy:0 Ready:1 | + * |-------------------------------------------------------------------------------------| + * | I/O 7 |Write protect |Write protect| Write protect |Write protect| Protect:0 Not:1| + * |-------------------------------------------------------------------------------------| + * + *************************************************************/ + +#include <nand.h> + +/** + * nand_read_id - Read the Nandflash ID + * @nand: The nand flash information + * return: The nandflash ID + */ +static unsigned short nand_read_id(void) +{ + unsigned short id = 0; + + nand_select(); /* chip Enable */ + nand_clear_RnB(); /*Clear Ready & Busy signal*/ + + REG_NFCMD = NAND_CMD_READID; /*Read ID command*/ + REG_NFADDR = 0x00; /*Give address 0x00*/ + id = REG_NFDATA; /*First byte, Maker code: 0xEC->Samsung*/ + id = (id << 8) | REG_NFDATA; /*Second byte, Device ID:0xDA->K9F2G08*/ + + /*We can read the followed 3 bytes(0x10,0x95,0x44) here, but it's useless.*/ + + nand_deselect(); + + return id; +} + +#define TACLS 1 // 1-clk +#define TWRPH0 4 // 4-clk +#define TWRPH1 1 // 1-clk //TACLS+TWRPH0+TWRPH1>=50ns + +/** + * nand_init - Initial the Nandflash controller and nand flash information structure "nand" + * @nand: The nand flash information + * Return: 0->success <0 failed + */ +int nand_init(struct boot_nand_t *nand) +{ + int i, ret = -1; + unsigned short nand_id; + + /*TACL=1, TWRPH0=4, TWRPH1=1, bit[0]=0 means the Nandflash bit witdth is 8bit(K9F2G08 is 8bit)*/ + REG_NFCONF= (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4)|(0<<0); + + /* + * Bit[13:12] No lock + * Bit[10:8] No nandflash interrupt + * Bit[6:4] Initialize ECC and lock data area & spare area ECC + * Bit[1] Enable nand flash chip select + * Bit[0] Enable nand flash controller + */ + REG_NFCONT= (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(1<<6)|(1<<5)|(1<<4)|(1<<1)|(1<<0); + + + for (i=0; i<10; i++) ; /*Wait tWB(100ns)*/ + + nand_id = nand_read_id(); + + /*K9F2G08 page/read/write size is 2K bytes, spare size is 64 bytes + * and block/erase size is 128K*/ + if ( NAND_K9F2G08 == nand_id ) /* Samsung K9F2G08 */ + { + /*1 Device = 2048 Blocks, 1 Block=64Pages, 1 Pages=(2K Bytes data+ 64Bytes spare)*/ + nand->id = NAND_K9F2G08; + nand->spare_size = 64; /* 64 bytes */ + nand->page_size = 0x0800; /* 1<<11=2K */ + nand->block_size = 0x20000; /* 1<<17=128K*/ + nand->block_num = 2048; /* 1<<17=128K*/ + /*Bad block tag is the first byte in spare area*/ + nand->bad_block_offset = nand->page_size; + ret = 0; + } + + return ret; +} + +/** + * nand_read_page - Read the data from a page main data area + * @nand: The nand flash information + * @page_num: The read page number + * @offset: The read data start offset address in the page + * @size: The request read data length + * @data: The read data output buffer + * Return: >=0 read bytes + */ +int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size) +{ + uchar *ptr = (uchar *)data; + ulong i, bytes; + + /*Avoid the offset+size larger than a page size(include main data and spare data size) */ + bytes = ((nand->page_size+nand->spare_size-offset)>=size ? size : (nand->page_size+nand->spare_size)-offset); + + nand_select(); + nand_clear_RnB(); + + REG_NFCMD = NAND_CMD_READ0; + /* Write Address */ + REG_NFADDR = 0; + REG_NFADDR = 0; + REG_NFADDR = page_num & 0xff; + REG_NFADDR = (page_num >> 8) & 0xff; + REG_NFADDR = (page_num >> 16) & 0xff; + REG_NFCMD = NAND_CMD_READSTART; + + /* + * After give NAND_CMD_READSTART command, when the RnB get a rising edge signal, it + * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] + * in nandflash controller. After get this signal, then we can read the data or send + * followed command + */ + nand_detect_RnB(); + + /* If the offset address in the page is 0 and need read a whole page, + * then we read the whole page, or use the random page read */ + if(0==offset && nand->page_size==size) + goto START_READ; + + /*Page Random Read will come here*/ + REG_NFCMD = NAND_CMD_RNDOUT; + REG_NFADDR = offset & 0xff; + REG_NFADDR = (offset >> 8) & 0xff; + REG_NFCMD = NAND_CMD_RNDOUTSTART; + +START_READ: + for(i=0; i<bytes; i++) + { + *ptr = REG_NFDATA; + ptr++; + } + + nand_deselect(); + return bytes; +} + + +/** + * nand_write_page - Write the data to a page main data area + * @nand: The nand flash information + * @page_num: The written page number + * @offset: The written data start offset address in the page + * @size: The written data length + * @data: The written data + * Return: >=0 write bytes + */ +int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size) +{ + uchar *ptr8 = (uchar *)data; + uchar stat; + int ret; + ulong i, bytes; + + /*Avoid the offset+size larger than a page size(include main data and spare data size) */ + bytes = ((nand->page_size+nand->spare_size-offset)>size ? size : (nand->page_size+nand->spare_size)-offset); + + nand_select(); + nand_clear_RnB(); + + REG_NFCMD = NAND_CMD_SEQIN; + /* Write Address */ + REG_NFADDR = 0; + REG_NFADDR = 0; + REG_NFADDR = page_num & 0xff; + REG_NFADDR = (page_num >> 8) & 0xff; + REG_NFADDR = (page_num >> 16) & 0xff; + + /* If the offset address in the page is 0 and need write a whole page data, + * then we read the whole page, or use the random page program */ + if(0==offset && nand->page_size==size) + goto START_PROG; + + /*Random page program will come here*/ + REG_NFCMD = NAND_CMD_RNDIN; + REG_NFADDR = offset & 0xff; + REG_NFADDR = (offset >> 8) & 0xff; + +START_PROG: + for(i=0; i<bytes; i++) + { + REG_NFDATA = *ptr8; + ptr8++; + } + REG_NFCMD = NAND_CMD_PAGEPROG; + + /* + * After give NAND_CMD_PAGEPROG command, when the RnB get a rising edge signal, it + * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] + * in nandflash controller. After get this signal, then we can send followed command. + */ + nand_detect_RnB(); + + /* When program operation is completed, the Write Status register Bit[I/O] 0 maybe checked, + * bit[0]=0 means pass, or bit[0]=1 means Fail. Refer the top table definition */ + REG_NFCMD = NAND_CMD_STATUS; + stat = REG_NFDATA; + if(stat & 0x01) + { + dbg_print("Random Program page number @%lu failure\n", page_num); + ret = -1; /*Program failure*/ + } + else + { + ret = bytes; + } + + nand_deselect(); + return ret; +} + + +/** + * is_bad_block - check the block which the "addr" in is valid or not + * @nand: Nandflash information + * @addr: The offset address in whole nandflash, no need block alignment + * Return: 1->bad block, 0->Valid block + */ +int is_bad_block(struct boot_nand_t *nand, ulong addr) +{ + char data; + ulong page_num; + ulong block_start; + int page_shift = generic_ffs(nand->page_size)-1; + + /*Get start address of the block wherre the "addr" in*/ + block_start = addr & (~(nand->block_size-1)); + + /* Get the first page number in the block, the Bad Block Tag is set in + * the first bit in the first page spare area in the block */ + page_num = block_start >> page_shift; + + nand_read_page(nand, page_num, nand->bad_block_offset, &data, 1); + + if (data != 0xff) + { + printf("Bad Block @%08lx by address @%08lx\n",block_start, addr); + nand_deselect(); + return 1; + } + + nand_deselect(); + return 0; +} + +/** + * mark_bad_block - Mark the block as bad block + * @nand: Nandflash information + * @addr: The offset address in whole nandflash, no need block alignment + * Return: 0->mark bad block success, <0 mark bad block failed. + */ +int mark_bad_block(struct boot_nand_t *nand, ulong addr) +{ + char data = 0xEE; + ulong page_num; + ulong block_num; + ulong block_start; + int ret; + + /*Get start address of the block wherre the "addr" in*/ + block_start = addr & (~(nand->block_size-1)); + + /* Get the first page number in the block, the Bad Block Tag is set in + * the first bit in the first page spare area in the block */ + page_num = block_start >> (generic_ffs(nand->page_size)-1); + + + ret = nand_write_page(nand, page_num, nand->bad_block_offset, &data, 1); + ret = ret<0 ? ret: 0; + + block_num = block_start >> (generic_ffs(nand->block_size)-1); + dbg_print("Mark bad block index [$%lu] address @0x%08lx %s.\n", + block_num, block_start, ret==0?"success":"failed"); + return ret; +} + +/** + * nand_erase_block - Erase a block specify by the block_num + * @nand: Nandflash information + * @block_num: The erase block index number + * Return: 0->success, <0 Failure + */ + +int nand_erase_block(struct boot_nand_t *nand, ulong block_num) +{ + uchar stat; + int ret = 0; + ulong block_start; /*Block start address*/ + + nand_select(); + nand_clear_RnB(); + + REG_NFCMD = NAND_CMD_ERASE1; + REG_NFADDR = (block_num<<6) & 0xff; /*Row address A18~A19*/ + REG_NFADDR = (block_num>>2) & 0xff; /*Row address A20~A27*/ + REG_NFADDR = (block_num>>10) & 0x0f; /*Row address A28*/ + REG_NFCMD = NAND_CMD_ERASE2; + + /* + * After give NAND_CMD_ERASE2 command, when the RnB get a rising edge signal, it + * will set(Read S3C2440 datasheet about NFCONT register) the NFSTAT register bit[2] + * in nandflash controller. After get this signal, then we can send next command. + */ + nand_detect_RnB(); + + /* When erase operation is completed, the Write Status register Bit[I/O] 0 maybe checked, + * bit[0]=0 means pass, or bit[0]=1 means Fail. Refer the top table definition */ + REG_NFCMD = NAND_CMD_STATUS; + + stat = REG_NFDATA; + + block_start = block_num<<(generic_ffs(nand->block_size)-1); + if( stat&(1<<0) ) + { + printf("Erase block index [$%lu] address @0x%08lx failed.\n", block_num, block_start); + mark_bad_block(nand, block_start); + ret = -1; + goto OUT; + } + + dbg_print("Erase block index [$%lu] address @0x%08lx success.\n", block_num, block_start); + +OUT: + nand_deselect(); + return ret; +} + + +/** + * nand_erase - Erase some blocks from start_addr + * @nand: Nandflash information + * @start_addr: The erase start address, it must be aligment + * @size: The erase block size, it must be n*block_size + * @skip_bad: Whether need auto skip the bad block or not, if skip, the erase size don't change + * Return: 0->success, >0 Bad block count + */ +int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad) +{ + + int block_num, ret=0; + int failed = 0; + ulong addr; + int block_shift = generic_ffs(nand->block_size)-1; + + if ( (start_addr & (nand->block_size-1)) || (size & (nand->block_size-1)) ) + { + printf("nand erase address @0x%08lx or size $%lu not block aligment.\n", start_addr, size); + return -1; /* invalid alignment */ + } + + addr = start_addr; + while( addr<(start_addr+size) ) + { + block_num = addr>> block_shift; + ret = nand_erase_block(nand, block_num); + if(ret < 0) + { + if(skip_bad) + { + /*Erase next block*/ + addr += nand->block_size; + size += nand->block_size; + continue; + } + else + { + failed ++; + } + } + else + addr += nand->block_size; + } + + /*If don't skip the bad block, then return the erase block failure times, or return OK.*/ + ret = (!skip_bad && failed) ? failed : 0; + + return ret; +} + +/* + * nand_scrub - nand erase the whole Nandflash + * @nand: The nand flash information + */ +void nand_scrub(struct boot_nand_t *nand) +{ + int i; + + for(i=0; i<nand->block_num; i++) + nand_erase_block(nand, i); +} + +/* nand_read_spare - Read some bytes from the spare first byte + * @nand: The nand flash information + * @page_addr: The page address in the whole Nand flash, no need page alignment + * @size: The spare area request read size, which start from the spare first byte + * @buf: The output data buffer + * Return: Read spare area data bytes + */ +int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf) +{ + ulong page_num; + ulong bytes; + int page_shift = generic_ffs(nand->page_size)-1; + + size = size > nand->spare_size ? nand->spare_size : size; + + page_num = page_addr >> page_shift; /*The page number in the whole Nandflash*/ + + bytes = nand_read_page(nand, page_num, nand->bad_block_offset, buf, size); + + return bytes; +} + +/* nand_write_spare - Write some bytes to the spare first byte + * @nand: The nand flash information + * @page_addr: The page address in the whole Nand flash, no need page alignment + * @size: The write data size + * @buf: The write data + * Return: Write to spare area data bytes + */ +int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf) +{ + ulong page_num; + ulong bytes; + int page_shift = generic_ffs(nand->page_size)-1; + + size = size > nand->spare_size ? nand->spare_size : size; + + page_num = page_addr >> page_shift; /*The page number in the whole Nandflash*/ + + bytes = nand_write_page(nand, page_num, nand->bad_block_offset, buf, size); + + return bytes; +} + +/** + * nand_read - Read some datas in the main data area in the page + * @nand: Nandflash information + * @start_addr: The read start address, it must be page alignment + * @size: The request read data size, no need alignment + * @buf: The read data output buffer + * Return: >=0 Read data bytes, <0 Read failure + */ +int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf) +{ + ulong addr; + ulong page_num; + ulong page_offset; + ulong page_mask = nand->page_size-1; + ulong bytes = 0; + ulong left; + int page_shift = generic_ffs(nand->page_size)-1; + + left = size; + addr = start_addr; + + /* The address must be page alignment*/ + if( (addr & page_mask) ) + { + printf("nand read address @0x%08lx not alignment.\n", addr); + return -1; + } + + while(left > 0) + { + /*If the addr is block alignment, then we check this block is valid or not*/ + if ( ((addr&(nand->block_size-1))==0) && is_bad_block(nand, addr) ) + { + /*Skip Bad block and goto next block */ + dbg_print("Skip bad block @0x%08lx\n", addr); + addr += nand->block_size; + continue; + } + + page_num = addr >> page_shift; /*The page number in the whole Nandflash*/ + page_offset = addr & page_mask; /*The offset address in the page*/ + + if( left >= nand->page_size) + { + bytes = nand_read_page(nand, page_num, page_offset, buf, nand->page_size); +#if 1 + dbg_print("Read whole page: addr=%08lx page_num=%d page_offset=%08lx, bytes=%lu \n", + addr, page_num, page_offset, bytes); +#endif + } + else + { + bytes = nand_read_page(nand, page_num, page_offset, buf, size%nand->page_size); +#if 1 + printf("Read part page: addr=%08lx page_num=%d page_offset=%d, bytes=%lu \n", + addr, page_num, page_offset, size%nand->page_size); +#endif + } + + addr+=bytes; + buf += bytes; + left-=bytes; + } + + return bytes; +} + + +/** + * nand_write - Write some datas to the main data area in the page + * @nand: Nandflash information + * @start_addr: The write start address, it must be page alignment + * @size: The write data size, no need alignment + * @buf: The write data + * Return: >=0 Write data bytes, <0 Write failure + */ +int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf) +{ + ulong addr; + ulong page_num; + ulong page_offset; + ulong page_mask = nand->page_size-1; + ulong bytes = 0; + ulong left; + int page_shift = generic_ffs(nand->page_size)-1; + + left = size; + addr = start_addr; + + /* The address must be page alignment*/ + if( (addr & page_mask) ) + { + printf("nand read address @0x%08lx not alignment.\n", addr); + return -1; + } + + while(left > 0) + { + /*If the addr is block alignment, then we check this block is valid or not*/ + if ( ((addr&(nand->block_size-1))==0) && is_bad_block(nand, addr) ) + { + /*Skip Bad block and goto next block */ + dbg_print("Skip bad block @0x%08lx\n", addr); + addr += nand->block_size; + continue; + } + + page_num = addr >> page_shift; /*The page number in the whole Nandflash*/ + page_offset = addr & page_mask; /*The offset address in the page*/ + + if( left >= nand->page_size) + { + bytes = nand_write_page(nand, page_num, page_offset, buf, nand->page_size); +#if 1 + dbg_print("Write whole page: addr=%08lx page_num=%d page_offset=%08lx, bytes=%lu \n", + addr, page_num, page_offset, bytes); +#endif + } + else + { + bytes = nand_write_page(nand, page_num, page_offset, buf, size%nand->page_size); +#if 1 + dbg_print("Write part page: addr=%08lx page_num=%d page_offset=%d, bytes=%lu \n", + addr, page_num, page_offset, size%nand->page_size); +#endif + } + + addr+=bytes; + buf += bytes; + left-=bytes; + } + + return bytes; +} + + +#if 0 + +/** + * nand_wait - wait Nandflash goes to Ready to operate + */ +static inline void nand_wait(void) +{ + int i; + + /*NFSTAG register bit[0] is RnB: 0->Nandflash Busy 1->Nandflash Ready to operate */ + while (!(REG_NFSTAT & NFSTAT_BUSY)) /*bit[0]*/ + { + dbg_print("Nandflash is busy.\n"); + for (i = 0; i < 10; i++) ; + } +} + + +/** + * nand_reset - Reset the Nandflash + */ +static void nand_reset(void) +{ + nand_select(); /* chip Enable */ + nand_clear_RnB(); /*Clear Ready & Busy signal*/ + + REG_NFCMD = NAND_CMD_RESET; /*Read ID command*/ + REG_NFADDR = 0x00; /*Give address 0x00*/ + + nand_detect_RnB(); + nand_deselect(); +} +#endif + diff --git a/linux-bsp/asm-study/myboot/led_beep.c b/linux-bsp/asm-study/myboot/led_beep.c new file mode 100644 index 0000000..64baba3 --- /dev/null +++ b/linux-bsp/asm-study/myboot/led_beep.c @@ -0,0 +1,56 @@ +/******************************************************************************************** + * File: led_beep.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: LED & Beep operate funciton. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#include <common.h> +#define DELAY_TIME 1000000 + +/*LED & Beep */ +#define GPBCON (*(unsigned long volatile *)0x56000010) +#define GPBDAT (*(unsigned long volatile *)0x56000014) +#define GPBUP (*(unsigned long volatile *)0x56000018) + +inline void delay(unsigned long loops) +{ + __asm__ volatile ("1:\n" "subs %0, %1, #1\n" "bne 1b":"=r" (loops):"0"(loops)); +} + +void init_led_beep(void) +{ + /* Set GPB5,GPB6,GPB8,GPB10 as GPIO mode(0x01) */ + GPBCON = (GPBCON | 0x333C03) & 0x111401; + GPBUP = (GPBUP | 0x560); + /* Set GPB5,GPB6,GPB8,GPB10 as high level, to turn LED0,LED1,LED2,LED3 off */ + GPBDAT = (GPBDAT | 0x560); +} + +void turn_led_on(int led) +{ + GPBDAT = (GPBDAT & (~(1 << led))); + delay(DELAY_TIME); +} + +void turn_led_off(int led) +{ + /* Turn LED0 on */ + GPBDAT = (GPBDAT | (1 << led)); + delay(DELAY_TIME); +} + +void beep(int count) +{ + int i; + for (i = 0; i < count; i++) + { + GPBDAT |= 1 << BEEP; /* Set Beep GPIO as high level */ + delay(DELAY_TIME * 50); + + GPBDAT &= ~(1 << BEEP); /* Set Beep GPIO as low level */ + delay(DELAY_TIME * 50); + } +} diff --git a/linux-bsp/asm-study/myboot/makefile b/linux-bsp/asm-study/myboot/makefile new file mode 100644 index 0000000..61ce521 --- /dev/null +++ b/linux-bsp/asm-study/myboot/makefile @@ -0,0 +1,118 @@ + +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM source code +# * ChangeLog: 1, Release initial version on "Sun Mar 20 18:41:04 CST 2011" +# * +# *********************************************************************** +# + +APP_NAME=bootstrap +#INST_PATH=/tftp + +# Enable "printf" function for help, don't enable it for production to save about 2K size +CONFIG_PRINTF_DBG=y + +# When wanna burn the image to nandflash and start from it, then commont follow option +RAM_DEBUG=y + +BOARD=SMDK2440 +#BOARD=SMDK2416 + +export BOARD + +SRC_TOP=$(CURDIR) + +CFLAGS+=-I${SRC_TOP}/include +CFLAGS+=-Os -D__KERNEL__ -DCONFIG_ARM -D__ARM__ -DBOARD_$(BOARD) +PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc + +ifeq ($(BOARD),SMDK2440) + PLATFORM_LIBS += -lc -L/opt/buildroot-2011.11/arm920t/usr/arm-unknown-linux-uclibcgnueabi/sysroot/usr/lib/ + ifeq ($(RAM_DEBUG),y) + TEXT_BASE=0x33000000 + else + TEXT_BASE=0x00000000 + endif +# Set the stack top base address here +CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) -DSTACK_BASE=0x33000000 +CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- +CFLAGS+= -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float +CFLAGS+=-march=armv4t -Wall -Wstrict-prototypes -fno-stack-protector +endif + +ifeq ($(BOARD),SMDK2416) +TEXT_BASE=0x33000000 +CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) +CROSS_COMPILE=/opt/buildroot-2011.11/arm926t/usr/bin/arm-linux- +CFLAGS+= -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float -mfloat-abi=soft +CFLAGS+=-march=armv4t -Wstrict-prototypes -fno-stack-protector +endif + +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +CC = $(CROSS_COMPILE)gcc +CPP = $(CC) -E +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +LDR = $(CROSS_COMPILE)ldr +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +RANLIB = $(CROSS_COMPILE)RANLIB + +gccincdir := $(shell $(CC) -print-file-name=include) +CFLAGS += -ffreestanding -nostdinc -isystem $(gccincdir) -pipe + +CFLAGS += -fno-builtin +LDFLAGS=-Bstatic -T$(APP_NAME).lds -Ttext $(TEXT_BASE) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ + +export CROSS_COMPILE AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP CFLAGS + +SOBJS := start.o mem_init.o +OBJS := bootstrap.o led_beep.o interrupt.o serial.o common.o xmodem.o k9f2g08.o + +ifeq ($(CONFIG_PRINTF_DBG), y) +CFLAGS+=-DCONFIG_PRINTF_DBG +endif + +ALL: .depend $(SOBJS) $(OBJS) + cd $(SRC_TOP) + ${LD} $(LDFLAGS) $(SOBJS) \ + --start-group $(OBJS) \ + --end-group $(PLATFORM_LIBS) \ + -Map $(APP_NAME).map -o $(APP_NAME).elf + ${OBJCOPY} -O binary $(APP_NAME).elf $(APP_NAME).bin + @chmod 777 $(APP_NAME).bin + @rm -f *.elf *.o + +.depend: makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(AFLAGS) -D__ASSEMBLY__ $(SOBJS:.o=.S) > $@ + $(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@ + +sinclude .depend + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: $(APP_NAME).bin + cp $(APP_NAME).bin $(INST_PATH) -f + cp $(APP_NAME).bin /tftp -f + +clean: + @find $(OBJTREE) -type f \ + \( -name 'core' -o -name '*.bak' -o -name '*~' -o -name .depend \ + -o -name '*.o' -o -name '*.a' -o -name '*.elf' \) -print \ + | xargs rm -f + @rm -f $(APP_NAME).bin + @rm -f $(APP_NAME).map + +distclean clear: clean + @rm -f cscope.* tags + + diff --git a/linux-bsp/asm-study/myboot/mem_init.S b/linux-bsp/asm-study/myboot/mem_init.S new file mode 100644 index 0000000..ddcce07 --- /dev/null +++ b/linux-bsp/asm-study/myboot/mem_init.S @@ -0,0 +1,170 @@ +/* + * Memory Setup stuff - taken from blob memsetup.S + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and + * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * + * Modified for the Samsung SMDK2410 by + * (C) Copyright 2002 + * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> + * + * Modified for the friendly-arm SBC-2410X by + * (C) Copyright 2005 + * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +/* + * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S + * + * Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com> + */ + +#include <config.h> + +#define BWSCON 0x48000000 + +/* BWSCON */ +#define DW8 (0x0) +#define DW16 (0x1) +#define DW32 (0x2) +#define WAIT (0x1<<2) +#define UBLB (0x1<<3) + +#define B1_BWSCON (DW16) +#define B2_BWSCON (DW16) +#define B3_BWSCON (DW16 + WAIT + UBLB) +#define B4_BWSCON (DW16) +#define B5_BWSCON (DW16) +#define B6_BWSCON (DW32) +#define B7_BWSCON (DW32) + +#define B0_Tacs 0x0 +#define B0_Tcos 0x0 +#define B0_Tacc 0x7 +#define B0_Tcoh 0x0 +#define B0_Tah 0x0 +#define B0_Tacp 0x0 +#define B0_PMC 0x0 + +#define B1_Tacs 0x0 +#define B1_Tcos 0x0 +#define B1_Tacc 0x7 +#define B1_Tcoh 0x0 +#define B1_Tah 0x0 +#define B1_Tacp 0x0 +#define B1_PMC 0x0 + +#define B2_Tacs 0x0 +#define B2_Tcos 0x0 +#define B2_Tacc 0x7 +#define B2_Tcoh 0x0 +#define B2_Tah 0x0 +#define B2_Tacp 0x0 +#define B2_PMC 0x0 + +#define B3_Tacs 0xc +#define B3_Tcos 0x7 +#define B3_Tacc 0xf +#define B3_Tcoh 0x1 +#define B3_Tah 0x0 +#define B3_Tacp 0x0 +#define B3_PMC 0x0 + +#define B4_Tacs 0x0 +#define B4_Tcos 0x0 +#define B4_Tacc 0x7 +#define B4_Tcoh 0x0 +#define B4_Tah 0x0 +#define B4_Tacp 0x0 +#define B4_PMC 0x0 + +#define B5_Tacs 0xc +#define B5_Tcos 0x7 +#define B5_Tacc 0xf +#define B5_Tcoh 0x1 +#define B5_Tah 0x0 +#define B5_Tacp 0x0 +#define B5_PMC 0x0 + +#define B6_MT 0x3 /* SDRAM */ +#define B6_Trcd 0x1 +#define B6_SCAN 0x1 /* 9bit */ + +#define B7_MT 0x3 /* SDRAM */ +#define B7_Trcd 0x1 /* 3clk */ +#define B7_SCAN 0x1 /* 9bit */ + +/* REFRESH parameter */ +#define REFEN 0x1 /* Refresh enable */ +#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ +#define Trc 0x3 /* 7clk */ +#define Tchr 0x2 /* 3clk */ + +#if defined(CONFIG_S3C2440) +#define Trp 0x2 /* 4clk */ +#define REFCNT 1012 +#else +#define Trp 0x0 /* 2clk */ +#define REFCNT 0x0459 +#endif +/**************************************/ + +_TEXT_BASE: + .word TEXT_BASE + +.globl mem_init +mem_init: + /* memory control configuration */ + /* make r0 relative the current location so that it */ + /* reads SMRDATA out of FLASH rather than memory ! */ + ldr r0, =SMRDATA + ldr r1, =mem_init + sub r0, r0, r1 + adr r3, mem_init /* r3 <- current position of code */ + add r0, r0, r3 + ldr r1, =BWSCON /* Bus Width Status Controller */ + add r2, r0, #13*4 +0: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r2, r0 + bne 0b + + /* everything is fine now */ + mov pc, lr + + .ltorg +/* the literal pools origin */ + +SMRDATA: + .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) + .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) + .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) + .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) + .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) + .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) + .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) + .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) + .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) + .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT) + .word 0xb2 + .word 0x30 + .word 0x30 diff --git a/linux-bsp/asm-study/myboot/nand.h b/linux-bsp/asm-study/myboot/nand.h new file mode 100644 index 0000000..9269296 --- /dev/null +++ b/linux-bsp/asm-study/myboot/nand.h @@ -0,0 +1,271 @@ +/* + * linux/include/linux/mtd/nand.h + * + * Copyright (c) 2000 David Woodhouse <dwmw2@infradead.org> + * Steven J. Hill <sjhill@realitydiluted.com> + * 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. + * + * Info: + * Contains standard defines and IDs for NAND flash devices + * + * Changelog: + * See git changelog. + */ +#ifndef __LINUX_MTD_NAND_H +#define __LINUX_MTD_NAND_H + +#include <common.h> +#include <linux/bitops.h> + +#define NAND_K9F2G08 0xecda + +/* This constant declares the max. oobsize / page, which + * is supported now. If you add a chip with bigger oobsize/page + * adjust this accordingly. + */ +#define NAND_MAX_OOBSIZE 218 +#define NAND_MAX_PAGESIZE 4096 + +/* + * Constants for hardware specific CLE/ALE/NCE function + * + * These are bits which can be or'ed to set/clear multiple + * bits in one go. + */ +/* Select the chip by setting nCE to low */ +#define NAND_NCE 0x01 +/* Select the command latch by setting CLE to high */ +#define NAND_CLE 0x02 +/* Select the address latch by setting ALE to high */ +#define NAND_ALE 0x04 + +#define NAND_CTRL_CLE (NAND_NCE | NAND_CLE) +#define NAND_CTRL_ALE (NAND_NCE | NAND_ALE) +#define NAND_CTRL_CHANGE 0x80 + +/* + * Standard NAND flash commands + */ +#define NAND_CMD_READ0 0x00 /*Page read period 1*/ +#define NAND_CMD_READSTART 0x30 /*Page read period 2, for large page*/ +#define NAND_CMD_READID 0x90 /*Read production ID*/ +#define NAND_CMD_SEQIN 0x80 /*Page write period 1*/ +#define NAND_CMD_PAGEPROG 0x10 /*Page write period 2*/ +#define NAND_CMD_ERASE1 0x60 /*Block erase period 1*/ +#define NAND_CMD_ERASE2 0xd0 /*Block erase period 2*/ +#define NAND_CMD_STATUS 0x70 /*Read status command*/ +#define NAND_CMD_RESET 0xff /*Nandflash reset command*/ +#define NAND_CMD_READ1 1 +#define NAND_CMD_RNDOUT 0x05 /*Page random read period 1*/ +#define NAND_CMD_RNDOUTSTART 0xE0 /*Page random read period 2*/ +#define NAND_CMD_RNDIN 0x85 /*Page random write*/ + +#define NAND_CMD_READOOB 0x50 +#define NAND_CMD_STATUS_MULTI 0x71 + +/* Extended commands for large page devices */ +#define NAND_CMD_CACHEDPROG 0x15 + +/* Extended commands for AG-AND device */ +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but + * there is no way to distinguish that from NAND_CMD_READ0 + * until the remaining sequence of commands has been completed + * so add a high order bit and mask it off in the command. + */ +#define NAND_CMD_DEPLETE1 0x100 +#define NAND_CMD_DEPLETE2 0x38 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_STATUS_ERROR 0x72 +/* multi-bank error status (banks 0-3) */ +#define NAND_CMD_STATUS_ERROR0 0x73 +#define NAND_CMD_STATUS_ERROR1 0x74 +#define NAND_CMD_STATUS_ERROR2 0x75 +#define NAND_CMD_STATUS_ERROR3 0x76 +#define NAND_CMD_STATUS_RESET 0x7f +#define NAND_CMD_STATUS_CLEAR 0xff + +#define NAND_CMD_NONE -1 + +/* Status bits */ +#define NAND_STATUS_FAIL 0x01 +#define NAND_STATUS_FAIL_N1 0x02 +#define NAND_STATUS_TRUE_READY 0x20 +#define NAND_STATUS_READY 0x40 +#define NAND_STATUS_WP 0x80 + +/* + * Constants for ECC_MODES + */ +typedef enum +{ + NAND_ECC_NONE, + NAND_ECC_SOFT, + NAND_ECC_HW, + NAND_ECC_HW_SYNDROME, + NAND_ECC_HW_OOB_FIRST, +} nand_ecc_modes_t; + +/* + * Constants for Hardware ECC + */ +/* Reset Hardware ECC for read */ +#define NAND_ECC_READ 0 +/* Reset Hardware ECC for write */ +#define NAND_ECC_WRITE 1 +/* Enable Hardware ECC before syndrom is read back from flash */ +#define NAND_ECC_READSYN 2 + +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE 0x80 + +/* Option constants for bizarre disfunctionality and real +* features +*/ +/* Chip can not auto increment pages */ +#define NAND_NO_AUTOINCR 0x00000001 +/* Buswitdh is 16 bit */ +#define NAND_BUSWIDTH_16 0x00000002 +/* Device supports partial programming without padding */ +#define NAND_NO_PADDING 0x00000004 +/* Chip has cache program function */ +#define NAND_CACHEPRG 0x00000008 +/* Chip has copy back function */ +#define NAND_COPYBACK 0x00000010 +/* AND Chip which has 4 banks and a confusing page / block + * assignment. See Renesas datasheet for further information */ +#define NAND_IS_AND 0x00000020 +/* Chip has a array of 4 pages which can be read without + * additional ready /busy waits */ +#define NAND_4PAGE_ARRAY 0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others. */ +#define BBT_AUTO_REFRESH 0x00000080 +/* Chip does not require ready check on read. True + * for all large page devices, as they do not support + * autoincrement.*/ +#define NAND_NO_READRDY 0x00000100 +/* Chip does not allow subpage writes */ +#define NAND_NO_SUBPAGE_WRITE 0x00000200 + +/* Options valid for Samsung large page devices */ +#define NAND_SAMSUNG_LP_OPTIONS \ + (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK) + +/* Macros to identify the above */ +#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR)) +#define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING)) +#define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) +#define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK)) +/* Large page NAND with SOFT_ECC should support subpage reads */ +#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \ + && (chip->page_shift > 9)) + +/* Mask to zero out the chip options, which come from the id table */ +#define NAND_CHIPOPTIONS_MSK (0x0000ffff & ~NAND_NO_AUTOINCR) + +/* Non chip related options */ +/* Use a flash based bad block table. This option is passed to the + * default bad block table function. */ +#define NAND_USE_FLASH_BBT 0x00010000 +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN 0x00020000 +/* This option is defined if the board driver allocates its own buffers + (e.g. because it needs them DMA-coherent */ +#define NAND_OWN_BUFFERS 0x00040000 +/* Options set by nand scan */ +/* bbt has already been read */ +#define NAND_BBT_SCANNED 0x40000000 +/* Nand scan has allocated controller struct */ +#define NAND_CONTROLLER_ALLOC 0x80000000 + +/* Cell info constants */ +#define NAND_CI_CHIPNR_MSK 0x03 +#define NAND_CI_CELLTYPE_MSK 0x0C + +/* + * NAND Flash Manufacturer ID Codes + */ +#define NAND_MFR_TOSHIBA 0x98 +#define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_NATIONAL 0x8f +#define NAND_MFR_RENESAS 0x07 +#define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad +#define NAND_MFR_MICRON 0x2c +#define NAND_MFR_AMD 0x01 + +/* +* Constants for oob configuration +*/ +#define NAND_SMALL_BADBLOCK_POS 5 +#define NAND_LARGE_BADBLOCK_POS 0 + + +#if defined(CONFIG_S3C2410) +#define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) +#define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x4) +#define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0x8) +#define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0xc) +#define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x10) +#define NFSTAT_BUSY 1 +#define nand_select() (REG_NFCONF &= ~0x800) /*Clear bit 11*/ +#define nand_deselect() (REG_NFCONF |= 0x800) +#define nand_clear_RnB() do {} while (0) +#define nand_detect_RnB() do {} while (0) +#define nand_wait_RnB() do {} while (0) + +#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) + +#define REG_NFCONF __REGi(ELFIN_NAND_BASE + 0x0) +#define REG_NFCONT __REGi(ELFIN_NAND_BASE + 0x4) +#define REG_NFCMD __REGb(ELFIN_NAND_BASE + 0x8) +#define REG_NFADDR __REGb(ELFIN_NAND_BASE + 0xc) +#define REG_NFDATA __REGb(ELFIN_NAND_BASE + 0x10) +#define REG_NFDATA16 __REGw(ELFIN_NAND_BASE + 0x10) +#define REG_NFSTAT __REGb(ELFIN_NAND_BASE + 0x20) +#define NFSTAT_BUSY 1 +#define nand_select() (REG_NFCONT &= ~(1 << 1)) +#define nand_deselect() (REG_NFCONT |= (1 << 1)) +#define nand_clear_RnB() (REG_NFSTAT |= (1 << 2)) +#define nand_detect_RnB() {while(!(REG_NFSTAT&(1<<2)));} /*Wait Read & Busy signal goto high(not busy)*/ +#define nand_wait_RnB() {while(!(REG_NFSTAT&(1<<0)));} /*Wait nand flash not busy, wait bit[0] goes to 1*/ + +#endif + +#define SKIP_BAD_BLOCK 1 +#define NOT_SKIP_BAD_BLOCK 0 + +struct boot_nand_t +{ + int page_size; + int spare_size; + int block_size; + int block_num; + int bad_block_offset; + int id; + // unsigned long size; +}; + +int nand_init(struct boot_nand_t *nand); +int nand_read_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); +int nand_write_page(struct boot_nand_t *nand, ulong page_num, ulong offset, char *data, ulong size); +int is_bad_block(struct boot_nand_t *nand, ulong addr); +int mark_bad_block(struct boot_nand_t *nand, ulong addr); +int nand_erase_block(struct boot_nand_t *nand, ulong block_num); +int nand_erase(struct boot_nand_t *nand, ulong start_addr, ulong size, int skip_bad); +void nand_scrub(struct boot_nand_t *nand); +int nand_read_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); +int nand_write_spare(struct boot_nand_t *nand, ulong page_addr, int size, char *buf); +int nand_read(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); +int nand_write(struct boot_nand_t *nand, ulong start_addr, ulong size, char *buf); + + + +#endif /* __LINUX_MTD_NAND_H */ diff --git a/linux-bsp/asm-study/myboot/rsa.c b/linux-bsp/asm-study/myboot/rsa.c new file mode 100644 index 0000000..fb5ca06 --- /dev/null +++ b/linux-bsp/asm-study/myboot/rsa.c @@ -0,0 +1,602 @@ +/* + * The RSA PK cryptosystem + * + * Copyright (C) 2006 Christophe Devine + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1 as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ +/* + * RSA was designed by Ron Rivest, Adi Shamir and Len Adleman. + * + * http://theory.lcs.mit.edu/~rivest/rsapaper.pdf + * http://www.cacr.math.uwaterloo.ca/hac/about/chap8.pdf + */ + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include <common.h> +#include <rsa.h> + +#if !defined(NO_GENPRIME) +/* + * Generate an RSA keypair + */ +int rsa_gen_key( rsa_context *ctx, int nbits, int exponent, + int (*rng_f)(void *), void *rng_d ) +{ + int ret; + mpi P1, Q1, H, G; + + if( nbits < 128 || exponent < 3 || rng_f == NULL ) + return( ERR_RSA_BAD_INPUT_DATA ); + + mpi_init( &P1, &Q1, &H, &G, NULL ); + + memset( ctx, 0, sizeof( rsa_context ) ); + + /* + * find primes P and Q with Q < P so that: + * GCD( E, (P-1)*(Q-1) ) == 1 + */ + CHK( mpi_lset( &ctx->E, exponent ) ); + + nbits >>= 1; + + do + { + CHK( mpi_gen_prime( &ctx->P, nbits, 0, rng_f, rng_d ) ); + CHK( mpi_gen_prime( &ctx->Q, nbits, 0, rng_f, rng_d ) ); + + if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) + mpi_swap( &ctx->P, &ctx->Q ); + + if( mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) + continue; + + CHK( mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); + CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); + CHK( mpi_gcd( &G, &ctx->E, &H ) ); + } + while( mpi_cmp_int( &G, 1 ) != 0 ); + + /* + * D = E^-1 mod ((P-1)*(Q-1)) + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + CHK( mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); + CHK( mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); + CHK( mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); + CHK( mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); + + ctx->len = ( mpi_size( &ctx->N ) + 7 ) >> 3; + +cleanup: + + mpi_free( &P1, &Q1, &H, &G, NULL ); + + if( ret != 0 ) + { + rsa_free( ctx ); + return( ERR_RSA_KEY_GEN_FAILED | ret ); + } + + return( 0 ); +} +#endif + +/* + * Perform an RSA public key operation + */ +int rsa_public( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ) +{ + int ret; + mpi T; + + // if( ilen != ctx->len || olen != ctx->len ) + // return( ERR_RSA_BAD_INPUT_DATA ); + + + mpi_init( &T, NULL ); + + CHK( mpi_import( &T, input, ilen ) ); + + if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + mpi_free( &T, NULL ); + return( ERR_RSA_BAD_INPUT_DATA ); + } + + CHK( mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + CHK( mpi_export( &T, output, olen ) ); + +cleanup: + + mpi_free( &T, NULL ); + + if( ret != 0 ) + return( ERR_RSA_PUBLIC_FAILED | ret ); + + return( 0 ); +} + +/* + * Perform an RSA private key operation + */ +int rsa_private( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ) +{ + int ret; + mpi T, T1, T2; + + //if( ilen != ctx->len || olen != ctx->len ) + // return( ERR_RSA_BAD_INPUT_DATA ); + + mpi_init( &T, &T1, &T2, NULL ); + + CHK( mpi_import( &T, input, ilen ) ); + + if( mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + mpi_free( &T, NULL ); + return( ERR_RSA_BAD_INPUT_DATA ); + } + +#if 0 + CHK( mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); +#else + /* + * faster decryption using the CRT + * + * T1 = input ^ dP mod P + * T2 = input ^ dQ mod Q + */ + CHK( mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); + CHK( mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (T1 - T2) * (Q^-1 mod P) mod P + */ + CHK( mpi_sub_mpi( &T, &T1, &T2 ) ); + CHK( mpi_mul_mpi( &T1, &T, &ctx->QP ) ); + CHK( mpi_mod_mpi( &T, &T1, &ctx->P ) ); + + /* + * output = T2 + T * Q + */ + CHK( mpi_mul_mpi( &T1, &T, &ctx->Q ) ); + CHK( mpi_add_mpi( &T, &T2, &T1 ) ); +#endif + + CHK( mpi_export( &T, output, olen ) ); + +cleanup: + + mpi_free( &T, &T1, &T2, NULL ); + + if( ret != 0 ) + return( ERR_RSA_PRIVATE_FAILED | ret ); + + return( 0 ); +} + +/* + * Check if the public key is valid + */ +int rsa_check_pubkey( rsa_context *ctx ) +{ + if( ( ctx->N.p[0] & 1 ) == 0 || + ( ctx->E.p[0] & 1 ) == 0 ) + return( ERR_RSA_KEY_CHK_FAILED ); + + if( mpi_size( &ctx->N ) < 128 || + mpi_size( &ctx->N ) > 4096 ) + return( ERR_RSA_KEY_CHK_FAILED ); + + if( mpi_size( &ctx->E ) < 2 || + mpi_size( &ctx->E ) > 64 ) + return( ERR_RSA_KEY_CHK_FAILED ); + + return( 0 ); +} + +/* + * Check if the private key is valid + */ +int rsa_check_privkey( rsa_context *ctx ) +{ + int ret = 0; + mpi TN, P1, Q1, H, G; + + mpi_init( &TN, &P1, &Q1, &H, &G, NULL ); + + CHK( mpi_mul_mpi( &TN, &ctx->P, &ctx->Q ) ); + CHK( mpi_sub_int( &P1, &ctx->P, 1 ) ); + CHK( mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + CHK( mpi_mul_mpi( &H, &P1, &Q1 ) ); + CHK( mpi_gcd( &G, &ctx->E, &H ) ); + + if( mpi_cmp_mpi( &TN, &ctx->N ) == 0 && + mpi_cmp_int( &G, 1 ) == 0 ) + { + mpi_free( &TN, &P1, &Q1, &H, &G, NULL ); + return( 0 ); + } + +cleanup: + + mpi_free( &TN, &P1, &Q1, &H, &G, NULL ); + return( ERR_RSA_KEY_CHK_FAILED | ret ); +} + +/* + * Add the PKCS#1 v1.5 padding and do a public RSA + */ +int rsa_pkcs1_encrypt( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ) +{ + int nb_pad; + unsigned char *p = output; + + if( *olen != ctx->len || *olen < ilen + 11 ) + { + return( ERR_RSA_BAD_INPUT_DATA ); + } + + nb_pad = *olen - 3 - ilen; + + *p++ = 0; + *p++ = RSA_CRYPT; + + while( nb_pad-- > 0 ) + { + do { *p = rand(); } while( *p == 0 ); + p++; + } + + *p++ = 0; + memcpy( p, input, ilen ); + + return( rsa_public( ctx, output, *olen, output, olen ) ); +} + +/* + * Do a private RSA, removes the PKCS#1 v1.5 padding + */ +int rsa_pkcs1_decrypt( rsa_context *ctx, + unsigned char *input, int ilen, + unsigned char *output, int *olen ) +{ + int ret; + unsigned char *p, buf[512]; + + if( ilen != ctx->len || ilen < 16 || ilen > 512 ) + return( ERR_RSA_BAD_INPUT_DATA ); + + if( ( ret = rsa_private( ctx, input, ilen, buf, &ilen ) ) != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 || *p++ != RSA_CRYPT ) + return( ERR_RSA_INVALID_PADDING ); + + while( *p != 0 ) + { + if( p >= buf + ilen - 1 ) + return( ERR_RSA_INVALID_PADDING ); + p++; + } + p++; + + if( *olen < ilen - (int)(p - buf) ) + return( ERR_RSA_INVALID_PADDING ); + + *olen = ilen - (int)(p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} + +/* + * Perform a private RSA to sign a message digest + */ +int rsa_pkcs1_sign( rsa_context *ctx, int alg_id, + unsigned char *hash, int hashlen, + unsigned char *sig, int siglen ) +{ + int nb_pad; + unsigned char *p = sig; + + if( siglen != ctx->len || siglen < 16 ) + return( ERR_RSA_BAD_INPUT_DATA ); + + switch( alg_id ) + { + case RSA_RAW: + nb_pad = siglen - 3 - hashlen; + break; + + case RSA_MD2: + case RSA_MD4: + case RSA_MD5: + nb_pad = siglen - 3 - 34; + break; + + case RSA_SHA1: + nb_pad = siglen - 3 - 35; + break; + + default: + return( ERR_RSA_BAD_INPUT_DATA ); + } + + if( nb_pad < 8 ) + return( ERR_RSA_BAD_INPUT_DATA ); + + *p++ = 0; + *p++ = RSA_SIGN; + + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + switch( alg_id ) + { + case RSA_RAW: + memcpy( p, hash, hashlen ); + break; + + case RSA_MD2: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 2; break; + + case RSA_MD4: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 4; break; + + case RSA_MD5: + memcpy( p, ASN1_HASH_MDX, 18 ); + memcpy( p + 18, hash, 16 ); + p[13] = 5; break; + + case RSA_SHA1: + memcpy( p, ASN1_HASH_SHA1, 15 ); + memcpy( p + 15, hash, 20 ); + break; + + default: + return( ERR_RSA_BAD_INPUT_DATA ); + } + + return( rsa_private( ctx, sig, siglen, sig, &siglen ) ); +} + +/* + * Perform a public RSA and check the message digest + */ +int rsa_pkcs1_verify( rsa_context *ctx, int alg_id, + unsigned char *hash, int hashlen, + unsigned char *sig, int siglen ) +{ + int ret, len; + unsigned char *p, c, buf[512]; + + if( siglen != ctx->len || siglen < 16 || siglen > 512 ) + return( ERR_RSA_BAD_INPUT_DATA ); + + if( ( ret = rsa_public( ctx, sig, siglen, buf, &siglen ) ) != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 || *p++ != RSA_SIGN ) + return( ERR_RSA_INVALID_PADDING ); + + while( *p != 0 ) + { + if( p >= buf + siglen - 1 || *p != 0xFF ) + return( ERR_RSA_INVALID_PADDING ); + p++; + } + p++; + + len = siglen - (int)( p - buf ); + + if( len == 34 ) + { + c = p[13]; + p[13] = 0; + + if( memcmp( p, ASN1_HASH_MDX, 18 ) != 0 ) + return( ERR_RSA_VERIFY_FAILED ); + + if( ( c == 2 && alg_id == RSA_MD2 ) || + ( c == 4 && alg_id == RSA_MD4 ) || + ( c == 5 && alg_id == RSA_MD5 ) ) + { + if( memcmp( p + 18, hash, 16 ) == 0 ) + return( 0 ); + else + return( ERR_RSA_VERIFY_FAILED ); + } + } + + if( len == 35 && alg_id == RSA_SHA1 ) + { + if( memcmp( p, ASN1_HASH_SHA1, 15 ) == 0 && + memcmp( p + 15, hash, 20 ) == 0 ) + return( 0 ); + else + return( ERR_RSA_VERIFY_FAILED ); + } + + if( len == hashlen && alg_id == RSA_RAW ) + { + if( memcmp( p, hash, hashlen ) == 0 ) + return( 0 ); + else + return( ERR_RSA_VERIFY_FAILED ); + } + + return( ERR_RSA_INVALID_PADDING ); +} + +/* + * Free the components of an RSA key + */ +void rsa_free( rsa_context *ctx ) +{ + mpi_free( &ctx->N, &ctx->E, &ctx->D, + &ctx->P, &ctx->Q, &ctx->DP, + &ctx->DQ, &ctx->QP, &ctx->RN, + &ctx->RP, &ctx->RQ, NULL ); +} + +//#include "md5.h" + +#define PTLEN 24 +#define CTLEN 128 + +/* + * Checkup routine + */ +int main ( void ) +{ + int len; + rsa_context rsa; + unsigned char md5sum[16]; + unsigned char rsa_plaintext[PTLEN]; + unsigned char rsa_decrypted[PTLEN]; + unsigned char rsa_ciphertext[CTLEN]; + + memset( &rsa, 0, sizeof( rsa ) ); + + rsa.len = 128; + + mpi_read( &rsa.N , "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79", 16 ); + + mpi_read( &rsa.E , "10001", 16 ); + mpi_read( &rsa.D , "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D", 16 ); + + mpi_read( &rsa.P , "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57", 16 ); + mpi_read( &rsa.Q , "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF", 16 ); + + mpi_read( &rsa.DP, "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725", 16 ); + mpi_read( &rsa.DQ, "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357", 16 ); + mpi_read( &rsa.QP, "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08", 16 ); + + printf( " RSA key validation: " ); + + if( rsa_check_pubkey( &rsa ) != 0 || + rsa_check_privkey( &rsa ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + + printf( "passed\n PKCS#1 encryption : " ); + + memcpy( rsa_plaintext, + "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD", PTLEN ); + + len = CTLEN; + if( rsa_pkcs1_encrypt( &rsa, rsa_plaintext, PTLEN, + rsa_ciphertext, &len ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + + printf( "passed\n PKCS#1 decryption : " ); + + len = sizeof( rsa_decrypted ); + + if( rsa_pkcs1_decrypt( &rsa, rsa_ciphertext, CTLEN, + rsa_decrypted, &len ) != 0 || + memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + + printf( "passed\n" ); + +#if 0 + md5_csum( rsa_plaintext, PTLEN, md5sum ); + + if( rsa_pkcs1_sign( &rsa, RSA_MD5, md5sum, 16, + rsa_ciphertext, CTLEN ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + + printf( "passed\n PKCS#1 sig. verify: " ); + + if( rsa_pkcs1_verify( &rsa, RSA_MD5, md5sum, 16, + rsa_ciphertext, CTLEN ) != 0 ) + { + printf( "failed\n" ); + return( 1 ); + } + + printf( "passed\n\n" ); +#endif + + rsa_free( &rsa ); + return( 0 ); +} diff --git a/linux-bsp/asm-study/myboot/serial.c b/linux-bsp/asm-study/myboot/serial.c new file mode 100644 index 0000000..5e7063a --- /dev/null +++ b/linux-bsp/asm-study/myboot/serial.c @@ -0,0 +1,74 @@ +/******************************************************************************************** + * File: serial.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: The UART on board drivers/functions. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#include <common.h> +#define GPHCON (*(unsigned long volatile *)0x56000070) + +void serial_init(void) +{ + S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; + + /*Enable UART0,UART1,UART2 */ + GPHCON = 0x0000aaaa; + + /*Set Parity, Stopbit etc. */ + uart->ULCON &= 0XFFFFFF00; + uart->ULCON |= 0X03; + + /*Disable modem */ + uart->UMCON = 0x0; + + /*Set UART FIFO control register */ + uart->UFCON = 0x00; + uart->UCON = 0x805; /*Enable FIFO */ + + /* + * UBRDIV = (UART Clock)/(baudrate*16) -1 + * = (50 000 000)/(115200*16) -1 + * = 26 + * = 0x1A + */ + uart->UBRDIV = 0x1A; +} + +void serial_send_byte(char c) +{ + S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; + /* wait for room in the tx FIFO */ + while (!(uart->UTRSTAT & 0x2)) ; + + uart->UTXH = c; + + if (c == '\n') /* If \n, also do \r */ + serial_send_byte('\r'); +} + +int serial_is_recv_enable(void) +{ + S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; + return uart->UTRSTAT & 0x1; +} + +int serial_recv_byte(void) +{ + S3C24X0_UART *const uart = (S3C24X0_UART *) ELFIN_UART_BASE; + + /* wait for character to arrive */ + while (!(uart->UTRSTAT & 0x1)) ; + + return uart->URXH & 0xff; +} + +void serial_puts(const char *s) +{ + while (*s) + { + serial_send_byte(*s++); + } +} diff --git a/linux-bsp/asm-study/myboot/start.S b/linux-bsp/asm-study/myboot/start.S new file mode 100644 index 0000000..05698d7 --- /dev/null +++ b/linux-bsp/asm-study/myboot/start.S @@ -0,0 +1,348 @@ + +/******************************************************************************************** + * File: start.S - Startup Code for ARM920 CPU-core + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: When system power up, the CPU will comes here to excute the first code here. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + +#include <config.h> + +.globl _start +_start: b start_code + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: .word undefined_instruction +_software_interrupt: .word software_interrupt +_prefetch_abort: .word prefetch_abort +_data_abort: .word data_abort +_not_used: .word not_used +_irq: .word irq +_fiq: .word fiq + + .balignl 16,0xdeadbeef + + +/* + ************************************************************************* + * + * Startup Code (called from the ARM reset exception vector) + * + * do important init only if we don't start from memory! + * relocate armboot to ram + * setup stack + * jump to second stage + * + ************************************************************************* + */ + +_TEXT_BASE: + .word TEXT_BASE + +.globl _armboot_start +_armboot_start: + .word _start + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +/* + * the actual start code + */ + +start_code: + /* + * set the cpu to SVC32 mode + */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0xd3 + msr cpsr, r0 + + /* Disable watchdog */ + ldr r0, =ELFIN_WATCHDOG_BASE + mov r1, #0 + str r1, [r0] + + /* Disable Interrupt */ + ldr r0, =ELFIN_INTERRUPT_BASE + mov r1, #0xffffffff + str r1, [r0, #INTMSK_OFFSET] + ldr r1, =0x000007ff + str r1, [r0, #INTSUBMSK_OFFSET] + + /* flush v4 I/D caches */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* disable MMU stuff and caches */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + mcr p15, 0, r0, c1, c0, 0 + + + /******************************************************************************************* + * Init system clock and power, FCLK:HCLK:PCLK = 1:4:8 + * Reference to S3C2440 datasheet: Chap 7 Clock&Power Management + * + * Initialize System Clock FCLK=400MHz HCLK=100MHz PCLK=50MHz + * FCLK is used by ARM920T + * HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, + * the interrupt controller, the LCD controller, the DMA and USB host block. + * PCLK is is used for APB bus,which is used by the peripherals such as WDT,IIS,I2C, + * PWM timer,MMC interface,ADC,UART,GPIO,RTC and SPI. + ******************************************************************************************/ + + /*Set LOCKTIME as default value 0x00ffffff*/ + ldr r0, =ELFIN_CLOCK_POWER_BASE + ldr r1, =0x00ffffff + str r1, [r0, #LOCKTIME_OFFSET] + + /******************************************************************************************* + * Reference to S3C2440 datasheet: Chap 7-8 ~ Page 242 + * + * Set the selection of Dividing Ratio between FCLK,HCLK and PCLK as FCLK:HCLK:PCLK = 1:4:8. + * This ratio is determined by HDIVN(here is 2) and PDIVN(here is 1) control register. + * Refer to the s3c2440 datasheet + *******************************************************************************************/ + ldr r0, =ELFIN_CLOCK_POWER_BASE + mov r1, #5 + str r1, [r0, #CLKDIVN_OFFSET] /*Set Clock Divider*/ + + mrc p15, 0, r1, c1, c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 + + /*************************************************************************************** + * Reference to S3C2440 datasheet: Chap 7-20 ~ Page 254 + * + * Set MPLLCON(0x4C000004) register as: + * [19:12]: MDIV(Main Divider control)=0x7F (value set in MDIV_405) + * [9:4]: PDIV(Pre-devider control)=0x02 (value set in PSDIV_405) + * [1:0]: SDIV(Post divider control)=0x01 (value set in PSDIV_405) + * + * MPLL(FCLK) = (2 * m * Fin)/(p * 2^s) + * m=(MDIV+8), p=(PDIV+2), s=SDIV + * + * So FCLK=((2*(127+8)*Fin)) / ((2+2)*2^1) + * = (2*135*12MHz)/8 + * = 405MHz + * For FCLK:HCLK:PCLK=1:4:8, so HCLK=100MHz, PCLK=50MHz + ***************************************************************************************/ + mov r1, #ELFIN_CLOCK_POWER_BASE + mov r2, #MDIV_405 + add r2, r2, #PSDIV_405 + str r2, [r1, #MPLLCON_OFFSET] + + /* Go to mem_init.S to Init memory controller register */ + bl mem_init + + /* Set up the stack */ +stack_setup: + ldr r0, =STACK_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ + sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo */ + sub sp, r0, #12 /* leave 3 words for abort-stack */ + bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ + +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0x00000000 /* clear */ + +clbss_l:str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + +#if 0 /*Don't wanna init BEEP & LED here*/ + bl init_led_beep + + /* + * R0,R1,R2 are the 1st,2nd, 3rd argument passed to C function + * If need pass more than 3 arguments, then we need use stack. + */ + mov r0,#LED1 + bl turn_led_on +#endif + + bl bootstrap_main + +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ + +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#define MODE_SVC 0x13 +#define I_BIT 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + + .macro bad_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + ldr r2, _armboot_start + sub r2, r2, #(CONFIG_STACKSIZE) + sub r2, r2, #(CONFIG_SYS_MALLOC_LEN) + /* set base 2 words into abort stack */ + sub r2, r2, #(CONFIG_SYS_GBL_DATA_SIZE+8) + ldmia r2, {r2 - r3} @ get pc, cpsr + add r0, sp, #S_FRAME_SIZE @ restore sp_SVC + + add r5, sp, #S_SP + mov r1, lr + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr + mov r0, sp + .endm + + .macro irq_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + add r7, sp, #S_PC + stmdb r7, {sp, lr}^ @ Calling SP, LR + str lr, [r7, #0] @ Save calling PC + mrs r6, spsr + str r6, [r7, #4] @ Save CPSR + str r0, [r7, #8] @ Save OLD_R0 + mov r0, sp + .endm + + .macro irq_restore_user_regs + ldmia sp, {r0 - lr}^ @ Calling r0 - lr + mov r0, r0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE + /* return & move spsr_svc into cpsr */ + subs pc, lr, #4 + .endm + + .macro get_bad_stack + ldr r13, _armboot_start @ setup our mode stack + sub r13, r13, #(CONFIG_STACKSIZE) + sub r13, r13, #(CONFIG_SYS_MALLOC_LEN) + /* reserve a couple spots in abort stack */ + sub r13, r13, #(CONFIG_SYS_GBL_DATA_SIZE+8) + + str lr, [r13] @ save caller lr / spsr + mrs lr, spsr + str lr, [r13, #4] + + mov r13, #MODE_SVC @ prepare SVC-Mode + @ msr spsr_c, r13 + msr spsr, r13 + mov lr, pc + movs pc, lr + .endm + + .macro get_irq_stack @ setup IRQ stack + ldr sp, IRQ_STACK_START + .endm + + .macro get_fiq_stack @ setup FIQ stack + ldr sp, FIQ_STACK_START + .endm + +/* + * exception handlers + */ + .align 5 +undefined_instruction: + get_bad_stack + bad_save_user_regs + bl do_undefined_instruction + + .align 5 +software_interrupt: + get_bad_stack + bad_save_user_regs + bl do_software_interrupt + + .align 5 +prefetch_abort: + get_bad_stack + bad_save_user_regs + bl do_prefetch_abort + + .align 5 +data_abort: + get_bad_stack + bad_save_user_regs + bl do_data_abort + + .align 5 +not_used: + get_bad_stack + bad_save_user_regs + bl do_not_used + + .align 5 +irq: + get_bad_stack + bad_save_user_regs + bl do_irq + + .align 5 +fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq diff --git a/linux-bsp/asm-study/myboot/xmodem.c b/linux-bsp/asm-study/myboot/xmodem.c new file mode 100644 index 0000000..36345b0 --- /dev/null +++ b/linux-bsp/asm-study/myboot/xmodem.c @@ -0,0 +1,121 @@ +/******************************************************************************************** + * File: xmodem.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: Xmodem protocal used to download the second stage bootloader(launcher) + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#include <common.h> + +#define XMODEM_SOH 0x01 /*Start Of Header, standard Xmodem */ +#define XMODEM_STX 0x02 /*1K-Modem start Xmodem */ +#define XMODEM_EOT 0x04 /*End Of Transmission */ +#define XMODEM_ACK 0x06 +#define XMODEM_NAK 0x15 +#define XMODEM_CAN 0x18 /*Stop transmission */ +#define XMODEM_EOF 0x1a /*CTRL+Z EOF */ + +#define XMODEM_BLOCK_SIZE 128 + +static int xmodem_wait(void) +{ + long cnt = 0; + + while (!serial_is_recv_enable()) + { + if (++cnt >= 2000000) + { + cnt = 0; + serial_send_byte(XMODEM_NAK); + } + } + return 0; +} + +static int xmodem_read_block(unsigned char block_number, char *buf) +{ + unsigned char c, block_num, check_sum; + int i; + + block_num = serial_recv_byte(); + if (block_num != block_number) + return -1; + + block_num ^= serial_recv_byte(); + if (block_num != 0xff) + return -1; + + check_sum = 0; + for (i = 0; i < XMODEM_BLOCK_SIZE; i++) + { + c = serial_recv_byte(); + *(buf++) = c; + check_sum += c; + } + + check_sum ^= serial_recv_byte(); + if (check_sum) + return -1; + + return i; +} + +long xmodem_recv(char *buf) +{ + int r, receiving = 0; + long size = 0; + unsigned char c, block_number = 1; + + while (1) + { + if (!receiving) + xmodem_wait(); + + c = serial_recv_byte(); + + switch (c) + { + case XMODEM_EOT: + serial_send_byte(XMODEM_ACK); + + /*Remove the CMPEOF */ + long cnt = 0; + if ((buf[-1] == XMODEM_EOF) && (buf[-2] == XMODEM_EOF) && (buf[-3] == XMODEM_EOF)) + { + while (size && buf[-cnt - 1] == XMODEM_EOF) + cnt++; + } + + size -= cnt; + goto RECV_OK; + + case XMODEM_CAN: + return -1; + + case XMODEM_SOH: + receiving++; + r = xmodem_read_block(block_number, buf); + if (r < 0) + { + serial_send_byte(XMODEM_NAK); + } + else + { + block_number++; + size += r; + buf += r; + serial_send_byte(XMODEM_ACK); + } + break; + + default: + if (receiving) + return -1; + } + } + + RECV_OK: + return size; +} diff --git a/linux-bsp/asm-study/yaffs2/bootstrap.c b/linux-bsp/asm-study/yaffs2/bootstrap.c new file mode 100644 index 0000000..d3077fb --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bootstrap.c @@ -0,0 +1,202 @@ +/******************************************************************************************** + * File: bootstrap.c + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This C code is the first stage bootloader(named bootstrap) + main code, test on FL2440 board. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <malloc.h> +#include "yaffsfs.h" +#include "s3c_board.h" + +#define MALLOC_SIZE 20 + +int mkdir(const char *mp, const char *name) +{ + char full_name[100]; + sprintf(full_name, "%s/%s", mp, name); + printf("Create directory [%s]\n", full_name); + return yaffs_mkdir(full_name, S_IREAD| S_IWRITE); +} + +int mkfile(const char *mp, const char *name) +{ + char full_name[100]; + char buf[100]; + int h; + + sprintf(full_name, "%s/%s", mp, name); + + h = yaffs_open(full_name, O_RDWR | O_CREAT | O_TRUNC, S_IREAD| S_IWRITE); + yaffs_write(h, name, strlen(name)); + yaffs_lseek(h, 0, SEEK_SET); + memset(buf, 0, sizeof(buf)); + yaffs_read(h, buf, sizeof(buf)); + printf("Create File [%s] content: [%s]\n", full_name, buf); + yaffs_close(h); + + return 0; +} + +int rm(const char *mp, const char *name) +{ + char full_name[100]; + + if(name) + sprintf(full_name, "%s/%s", mp, name); + else + strcpy(full_name, mp); + + printf("Remove %s\n", full_name); + return yaffs_rm(full_name, 1); +} + +int ls(const char *mp, const char *name) +{ + int recursive = 1; + char full_name[100]; + + if(name) + sprintf(full_name, "%s/%s", mp, name); + else + strcpy(full_name, mp); + + printf("List folder '%s' %s recursive:\n", full_name, recursive?"with":"without"); + return yaffs_ls(full_name, recursive); +} + + +void dump_directory_tree_worker(const char *dname,int recursive) +{ + yaffs_DIR *d; + struct yaffs_dirent *de; + struct yaffs_stat s; + char str[1000]; + + d = yaffs_opendir(dname); + + if(!d) + { + printf("opendir failed\n"); + } + else + { + while((de = yaffs_readdir(d)) != NULL) + { + sprintf(str,"%s/%s",dname,de->d_name); + + yaffs_lstat(str,&s); + + printf("%s inode %d obj %x length %lld mode %X ", + str,s.st_ino,de->d_dont_use, s.st_size,s.st_mode); + switch(s.st_mode & S_IFMT) + { + case S_IFREG: printf("data file"); break; + case S_IFDIR: printf("directory"); break; + case S_IFLNK: printf("symlink -->"); + if(yaffs_readlink(str,str,100) < 0) + printf("no alias"); + else + printf("\"%s\"",str); + break; + default: printf("unknown"); break; + } + printf("\n"); + + if((s.st_mode & S_IFMT) == S_IFDIR && recursive) + dump_directory_tree_worker(str,1); + } + + yaffs_closedir(d); + } +} + + +static void dump_directory_tree(const char *dname) +{ + dump_directory_tree_worker(dname,1); + printf("\n"); + printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); +} + +void dumpDir(const char *dname) +{ + dump_directory_tree_worker(dname,0); + printf("\n"); + printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); +} + + +void yaffs_test(const char *mountpt) +{ + yaffs_start_up(); + +#if 0 + yaffs_mount(mountpt); + ls(mountpt, NULL); + + mkdir(mountpt, "foo"); + mkfile(mountpt, "foo/f1"); + + return ; +#endif + + yaffs_format(mountpt,0,0,0); + + yaffs_mount(mountpt); + printf("'%s' mounted\n", mountpt); + + mkdir(mountpt, "foo"); + mkfile(mountpt, "foo/f1"); + + mkfile(mountpt, "foo/f2"); + mkfile(mountpt, "foo/f3"); + mkfile(mountpt, "foo/f4"); + + mkdir(mountpt, "bar"); + mkfile(mountpt, "bar/f1"); + ls(mountpt, NULL); + + rm(mountpt, "foo/f4"); + rm(mountpt, "bar"); + ls(mountpt, NULL); + + printf("unmount and remount\n\n"); + + /* Unmount/remount yaffs_trace_mask */ + yaffs_unmount(mountpt); + yaffs_mount(mountpt); + ls(mountpt, NULL); +} + +int bootstrap_main(void) +{ + char *ptr = NULL; + int rv = -1; + + console_serial_init(); + printf("\b\n"); + printf("\bBootstrap nandflash yaffs2 test Version 0.0.1\n"); + + /* armboot_start is defined in the board-specific linker script */ + mem_malloc_init (TEXT_BASE - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN); + + ptr = (char *)malloc(MALLOC_SIZE); + strncpy(ptr, "Hello World!\n", MALLOC_SIZE); + printf("Malloc address: %p, string: %s\n", ptr, ptr); + free(ptr); + + yaffs_test(YAFFSFS_MNT_POINT); + +hang: + while(1) + ; + + return 0; +} + diff --git a/linux-bsp/asm-study/yaffs2/bootstrap.lds b/linux-bsp/asm-study/yaffs2/bootstrap.lds new file mode 100644 index 0000000..810e0a7 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bootstrap.lds @@ -0,0 +1,32 @@ +/******************************************************************************************** + * File: bootstrap.lds + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: This is the LD linker configure script for bootstrap + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +SECTIONS{ + . = ALIGN(4); + .text : + { + start.o (.text) + *(.text) + } + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + . = ALIGN(4); + .rodata : { *(.rodata) } + . = ALIGN(4); + .data : { *(.data) } + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} + diff --git a/linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c b/linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c new file mode 100644 index 0000000..61949e3 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/eabi_compat.c @@ -0,0 +1,29 @@ +/* + * Utility functions needed for (some) EABI conformant tool chains. + * + * (C) Copyright 2009 Wolfgang Denk <wd@denx.de> + * + * 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 <stdio.h> + +#if 1 +int raise (int signum) +{ +// printf("raise: Signal # %d caught\n", signum); + return 0; +} + +/* Dummy function to avoid linker complaints */ +void __aeabi_unwind_cpp_pr0(void) +{ +}; +#else +void __aeabi_unwind_cpp_pr1(void) +{ +}; +#endif diff --git a/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c new file mode 100644 index 0000000..1db8432 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.c @@ -0,0 +1,276 @@ +/* +| ECC MAIN | BAD | RES | YAFFS_TAG | +| 4 | 4 | 8 | 48 | +*/ + +#include "k9f2g08_s3c.h" + +/* From yaffs_guts.h */ +#define YAFFS_OK 1 +#define YAFFS_FAIL 0 + + +int k9f2g08_init(void) +{ + return YAFFS_OK; +} + +int k9f2g08_deinit(void) +{ + return YAFFS_OK; +} + +static unsigned char wait_busy_status(void) +{ + unsigned char rc; + + for (rc=0; rc <40; rc++); + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x70); // read status + do { + rc = bsp_nand_read_data8(); + } while ((rc & (1<<6)) == 0); + bsp_nand_set_cs(1); + + return rc; +} + +int k9f2g08_mark_block_bad(unsigned int blk_num) +{ + int row_addr = blk_num * 64; + int col_addr = 2048; + + unsigned char status; + + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x80); // write command + bsp_nand_write_addr((unsigned char)(col_addr >> 0)); + bsp_nand_write_addr((unsigned char)(col_addr >> 8)); + bsp_nand_write_addr((unsigned char)(row_addr >> 0)); + bsp_nand_write_addr((unsigned char)(row_addr >> 8)); + bsp_nand_write_addr((unsigned char)(row_addr >> 16)); + + bsp_nand_write_data32(0xFFFFFFFF); + bsp_nand_write_data32(0x00000000); + bsp_nand_write_data32(0xFFFFFFFF); + bsp_nand_write_data32(0xFFFFFFFF); + bsp_nand_write_cmd(0x10); + bsp_nand_set_cs(1); + + status = wait_busy_status(); + + return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK; +} + +int k9f2g08_write(unsigned int chunk, const unsigned char *dat, const unsigned char *spare, unsigned int spare_size) +{ + int i; + int col_addr; + unsigned char status; + + if (dat) { + col_addr = 0; + } else { + col_addr = 2048; + } + + + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x80); // write command + bsp_nand_write_addr((unsigned char)(col_addr >> 0)); + bsp_nand_write_addr((unsigned char)(col_addr >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 0)); + bsp_nand_write_addr((unsigned char)(chunk >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 16)); + + bsp_nand_start_main_ecc(); + if (dat) { + for (i=0; i<2048; i++) + bsp_nand_write_data8(*dat++); + } + + bsp_nand_stop_main_ecc(); + + bsp_nand_write_data32(bsp_nand_read_spare_ecc0()); + bsp_nand_write_data32(0xFFFFFFFF); + bsp_nand_write_data32(0xFFFFFFFF); + bsp_nand_write_data32(0xFFFFFFFF); + + if (spare) { + for (i=0; i<spare_size; i++) + bsp_nand_write_data8(*spare++); + } + + bsp_nand_write_cmd(0x10); + bsp_nand_set_cs(1); + + status = wait_busy_status(); + + return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK; +} + +int k9f2g08_read(unsigned int chunk, unsigned char *dat, unsigned char *spare, unsigned int spare_size, int *eccStatus) +{ + int i; + int col_addr; + unsigned char *p = dat; + unsigned int ecc = 0; + int err_bit; + int err_byte; + + if (dat) { + col_addr = 0; + } else { + col_addr = 2048 + 16; + } + + + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x00); // read command + bsp_nand_write_addr((unsigned char)(col_addr >> 0)); + bsp_nand_write_addr((unsigned char)(col_addr >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 0)); + bsp_nand_write_addr((unsigned char)(chunk >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 16)); + bsp_nand_write_cmd(0x30); // read + bsp_nand_wait_busy(); + + if (dat) { + bsp_nand_start_main_ecc(); + for (i=0; i<2048; i++) + *p++ = bsp_nand_read_data8(); + + bsp_nand_stop_main_ecc(); + + ecc = bsp_nand_read_data32(); + + bsp_nand_read_data32(); + bsp_nand_read_data32(); + bsp_nand_read_data32(); + } + if (spare) { + p = spare; + for (i=0; i<spare_size; i++) + *p++ = bsp_nand_read_data8(); + } + + bsp_nand_set_cs(1); + + if (dat) { + i = bsp_nand_main_check_ecc(ecc, &err_byte, &err_bit); + if (i == 0) { + *eccStatus = 0; + return 0; + } + + if (i < 0) { + *eccStatus = -1; + return 0; + } + + *eccStatus = 1; + dat[err_byte] ^= (1<<err_bit); + } + + return YAFFS_OK; +} + +int k9f2g08_erase_block(unsigned int blk_num) +{ + unsigned char status; + int chunk = blk_num * 64; + + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x60); // erase command + bsp_nand_write_addr((unsigned char)(chunk >> 0)); + bsp_nand_write_addr((unsigned char)(chunk >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 16)); + bsp_nand_write_cmd(0xD0); // erase + bsp_nand_set_cs(1); + + status = wait_busy_status(); + return (status & (1<<0)) ? YAFFS_FAIL : YAFFS_OK; +} + +int k9f2g08_is_block_ok(unsigned int blk_num) +{ + int chunk = blk_num * 64; + int col_addr = 2048 + 4; + + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x00); // read command + bsp_nand_write_addr((unsigned char)(col_addr >> 0)); + bsp_nand_write_addr((unsigned char)(col_addr >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 0)); + bsp_nand_write_addr((unsigned char)(chunk >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 16)); + bsp_nand_write_cmd(0x30); // read + bsp_nand_wait_busy(); + + int tmp = bsp_nand_read_data32(); + bsp_nand_set_cs(1); + + if (tmp == 0xFFFFFFFF) { + return 1; + } + return 0; +} + + +int k9f2g08_read_id(unsigned int *id) +{ + int rc = -1; + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x90); // read command + bsp_nand_write_addr((unsigned char)0); + do { + if ((rc = bsp_nand_read_data8()) != 0xEC) + break; + *id = bsp_nand_read_data32(); + rc = 0; + } while(0); + + bsp_nand_set_cs(1); + + return rc; +} + +int k9f2g08_read_ll(unsigned int chunk, unsigned char *dat, unsigned char *spare) +{ + int i; + int col_addr; + unsigned char *p; + + if (dat) { + col_addr = 0; + } else { + col_addr = 2048; + } + + + bsp_nand_set_cs(0); + bsp_nand_write_cmd(0x00); // read command + bsp_nand_write_addr((unsigned char)(col_addr >> 0)); + bsp_nand_write_addr((unsigned char)(col_addr >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 0)); + bsp_nand_write_addr((unsigned char)(chunk >> 8)); + bsp_nand_write_addr((unsigned char)(chunk >> 16)); + bsp_nand_write_cmd(0x30); // read + + bsp_nand_wait_busy(); + + if (dat) { + p = dat; + for (i=0; i<2048; i++) + *p++ = bsp_nand_read_data8(); + } + if (spare) { + p = spare; + for (i=0; i<64; i++) + *p++ = bsp_nand_read_data8(); + } + + bsp_nand_set_cs(1); + + return 1; +} diff --git a/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h new file mode 100644 index 0000000..e3f7af8 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_api.h @@ -0,0 +1,14 @@ +#ifndef __K9F2G08_API_H__ +#define __K9F2G08_API_H__ + +int k9f2g08_init(void); +int k9f2g08_deinit(void); +int k9f2g08_mark_block_bad(unsigned int blk_num); +int k9f2g08_write(unsigned int chunk, const unsigned char *dat, const unsigned char *spare, unsigned int spare_size); +int k9f2g08_read(unsigned int chunk, unsigned char *dat, unsigned char *spare, unsigned int spare_size, int *eccStatus); +int k9f2g08_read_ll(unsigned int chunk, unsigned char *dat, unsigned char *spare); +int k9f2g08_erase_block(unsigned int blk_num); +int k9f2g08_is_block_ok(unsigned int blk_num); +int k9f2g08_read_id(unsigned int *id); + +#endif // __K9F2G08_API_H__ diff --git a/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h new file mode 100644 index 0000000..a627766 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/k9f2g08_s3c.h @@ -0,0 +1,177 @@ +#ifndef __K9F2G08_S3C_H__ +#define __K9F2G08_S3C_H__ + +#include "s3c2440.h" + +static inline void bsp_init_nand(void) +{ + unsigned int reg; + + struct s3c2440_clock_power *clkpwr = s3c2440_get_base_clock_power(); + clkpwr->CLKCON |= (1<<4); + + struct s3c2440_gpio *gpio = s3c2440_get_base_gpio(); + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + + reg = gpio->GPACON; + reg |= (1<<22) | (1<<20) | (1<<19) | (1<<18) | (1<<17); + gpio->GPACON = reg; + + nand->NFCONF = (1<<12) | (1<<8) | (1<<4) | (1<<3) |(1<<2) | (1<<5) | (0<<0); + nand->NFCONT = 3; +} + +static inline void bsp_nand_set_cs(int level) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + if (level == 0) { + nand->NFCONT &= ~(1<<1); +// while (nand->NFSTAT & (1<<1)); + } else { + nand->NFCONT |= 1<<1; +// while ((nand->NFSTAT & (1<<1)) == 0); + } +} + +static inline void bsp_nand_start_main_ecc(void) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + nand->NFCONT |= (1<<6) | (1<<5); // unlock all + nand->NFCONT |= (1<<4); // init ecc + nand->NFCONT &= ~(1<<6); // lock spare +} + +static inline void bsp_nand_stop_main_ecc(void) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + nand->NFCONT |= (1<<5); // lock main +} + +static inline void bsp_nand_start_spare_ecc(void) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + nand->NFCONT &= ~(1<<6); // unlock spare +} + +static inline void bsp_nand_stop_spare_ecc(void) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + nand->NFCONT |= (1<<6); // lock spare +} + +static inline int bsp_nand_spare_check_ecc(unsigned short ecc, int *err_byte, int *err_bit) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + unsigned int ecc_wr = ((ecc & 0xFF00) << 8) | (ecc & 0x00FF); + + nand->NFSECCD = ecc_wr; + int err = nand->NFESTAT0; + + if ((err & (3<<2)) == (0<<2)) // no err + return 0; + + + if ((err & (3<<2)) == (1<<2)) { // 1 bit err + *err_byte = (err >> 21) & 0x0F; + *err_bit = (err >> 18) & 0x07; + return 1; + } + + return -1; + +} + +static inline int bsp_nand_main_check_ecc(unsigned int ecc, int *err_byte, int *err_bit) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + + unsigned int ecc_wr = ((ecc & 0xFF00) << 8) | (ecc & 0x00FF); + nand->NFMECCD0 = ecc_wr; + + ecc_wr = ((ecc & 0xFF000000) >> 8) | ((ecc & 0x00FF0000) >> 16); + nand->NFMECCD1 = ecc_wr; + + int err = nand->NFESTAT0; + + if ((err & (3<<0)) == (0<<0)) // no err + return 0; + + + if ((err & (3<<0)) == (1<<0)) { // no err + *err_byte = (err >> 7) & 0x7FF; + *err_bit = (err >> 4) & 0x07; + return 1; + } + + return -1; +} + + +static inline void bsp_nand_write_cmd(unsigned char cmd) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + nand->NFCMD = cmd; +} + + +static inline void bsp_nand_write_addr(unsigned char addr) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + nand->NFADDR = addr; +} + +static inline void bsp_nand_write_data32(unsigned int dat) +{ + *(volatile unsigned int *)(&(s3c2440_get_base_nand()->NFDATA)) = dat; +} + + +static inline void bsp_nand_write_data16(unsigned short dat) +{ + *(volatile unsigned short *)(&(s3c2440_get_base_nand()->NFDATA)) = dat; +} + +static inline void bsp_nand_write_data8(unsigned char dat) +{ + *(volatile unsigned char *)(&(s3c2440_get_base_nand()->NFDATA)) = dat; +} + + +static inline unsigned int bsp_nand_read_data32(void) +{ + return *(volatile unsigned int *)(&(s3c2440_get_base_nand()->NFDATA)); +} + + +static inline unsigned short bsp_nand_read_data16(void) +{ + return *(volatile unsigned short *)(&(s3c2440_get_base_nand()->NFDATA)); +} + +static inline unsigned char bsp_nand_read_data8(void) +{ + return *(volatile unsigned char *)(&(s3c2440_get_base_nand()->NFDATA)); +} + +static inline unsigned short bsp_nand_read_spare_ecc0(void) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + return nand->NFSECC & 0xFFFF; +} + +static inline unsigned int bsp_nand_read_main_ecc0(void) +{ + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + return nand->NFMECC0; +} + + +static inline void bsp_nand_wait_busy(void) +{ + int i; + for (i=10; i>0; i--); + struct s3c2440_nand *nand = s3c2440_get_base_nand(); + while ((nand->NFSTAT & (1<<0)) == 0); +} + +#endif //__K9F2G08_S3C_H__ diff --git a/linux-bsp/asm-study/yaffs2/bsp/makefile b/linux-bsp/asm-study/yaffs2/bsp/makefile new file mode 100644 index 0000000..be21cdc --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/makefile @@ -0,0 +1,102 @@ +#********************************************************************************* +# Copyright: (C) 2012 CoherentPlus Sdn. Bhd. +# All rights reserved. +# +# Filename: Makefile +# Description: This is the common subdir Makefile which to compile all the C +# source code to object files and then generate the shared or +# static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so, +# which depends on the variable $LINK_MODE. +# +# Version: 1.0.0(10/08/2011~) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "10/08/2011 01:29:33 AM" +# +#********************************************************************************/ + +PWD=$(shell pwd) +LOCAL_COMPILE=YES +LINK_MODE=STATIC + +#If wanna compile in the subdir, not called by top makefile, uncomment it +ifneq (${TOP_COMPILE}, YES) +LOCAL_COMPILE=YES +endif + +LIBNAME=$(shell basename ${PWD}) +STALIB=lib${LIBNAME}.a +DYNLIB=lib${LIBNAME}.so + +VPATH= . +C_SRCS = $(wildcard ${VPATH}/*.c) +AS_SRCS = $(wildcard ${VPATH}/*.S) +OBJS = $(patsubst %.c,%.o,$(C_SRCS)) +OBJS += $(patsubst %.S,%.o,$(AS_SRCS)) + +#====================================================== +# ---> Doesn't call by top makefile, compile by local +#====================================================== +ifeq (${LOCAL_COMPILE}, YES) +ARCH?=arm920t +#ARCH?=i386 +CFLAGS+=-fPIC +TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") +ifneq (,$(filter i386,$(TMP))) + CROSS_COMPILE= +else + CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- +endif + +PRJDIR?=$(shell pwd) +CFLAGS+=-I${PRJDIR} +CC = ${CROSS_COMPILE}gcc +AR = ${CROSS_COMPILE}ar + +endif #End local compile + +ifeq ("${LINK_MODE}", "STATIC") + LIBS = ${STALIB} +else + LIBS=${DYNLIB} +endif + +all: entry ${LIBS} install + +entry: + @echo " "; + @echo " ========================================================="; + @echo " ** Compile subdir ${LIBNAME} for ${ARCH} "; + @echo " ========================================================="; + +#$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o +${STALIB}: $(OBJS) + $(AR) -rcu $@ $(OBJS) + +${DYNLIB}: $(OBJS) + $(CC) -fPIC -shared -o $@ $(OBJS) + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< + +%.o : %.c + $(CC) -c $< $(CFLAGS) + +tag: + @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . + @cscope -Rbq + +install: + @if [ ! -z "${LIBS_PATH}" ] ; then \ + mkdir -p ${LIBS_PATH} ; \ + cp ${LIBS} ${LIBS_PATH}; \ + fi; + + +clean: + @rm -f *.o + @rm -rf *.gdb *.a *.so + +distclean: clean + @rm -f tags cscope* + +.PHONY: clean entry diff --git a/linux-bsp/asm-study/yaffs2/bsp/s3c2440.h b/linux-bsp/asm-study/yaffs2/bsp/s3c2440.h new file mode 100644 index 0000000..0a46bc9 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/s3c2440.h @@ -0,0 +1,646 @@ +#ifndef __S3C2440_H__ +#define __S3C2440_H__ + +#define S3C2440_UART_CHANNELS 3 +#define S3C2440_SPI_CHANNELS 2 + +/* Memory controller (see manual chapter 5) */ +struct s3c2440_memctl { + volatile unsigned int BWSCON; + volatile unsigned int BANKCON[8]; + volatile unsigned int REFRESH; + volatile unsigned int BANKSIZE; + volatile unsigned int MRSRB6; + volatile unsigned int MRSRB7; +}; + + +/* USB HOST (see manual chapter 12) */ +struct s3c2440_usb_host { + volatile unsigned int HcRevision; + volatile unsigned int HcControl; + volatile unsigned int HcCommonStatus; + volatile unsigned int HcInterruptStatus; + volatile unsigned int HcInterruptEnable; + volatile unsigned int HcInterruptDisable; + volatile unsigned int HcHCCA; + volatile unsigned int HcPeriodCuttendED; + volatile unsigned int HcControlHeadED; + volatile unsigned int HcControlCurrentED; + volatile unsigned int HcBulkHeadED; + volatile unsigned int HcBuldCurrentED; + volatile unsigned int HcDoneHead; + volatile unsigned int HcRmInterval; + volatile unsigned int HcFmRemaining; + volatile unsigned int HcFmNumber; + volatile unsigned int HcPeriodicStart; + volatile unsigned int HcLSThreshold; + volatile unsigned int HcRhDescriptorA; + volatile unsigned int HcRhDescriptorB; + volatile unsigned int HcRhStatus; + volatile unsigned int HcRhPortStatus1; + volatile unsigned int HcRhPortStatus2; +}; + + +/* INTERRUPT (see manual chapter 14) */ +struct s3c2440_interrupt { + volatile unsigned int SRCPND; + volatile unsigned int INTMOD; + volatile unsigned int INTMSK; + volatile unsigned int PRIORITY; + volatile unsigned int INTPND; + volatile unsigned int INTOFFSET; + volatile unsigned int SUBSRCPND; + volatile unsigned int INTSUBMSK; +}; + + +/* DMAS (see manual chapter 8) */ +struct s3c2440_dma { + volatile unsigned int DISRC; + volatile unsigned int DISRCC; + volatile unsigned int DIDST; + volatile unsigned int DIDSTC; + volatile unsigned int DCON; + volatile unsigned int DSTAT; + volatile unsigned int DCSRC; + volatile unsigned int DCDST; + volatile unsigned int DMASKTRIG; + volatile unsigned int res[7]; +}; + +struct s3c2440_dmas { + struct s3c2440_dma dma[4]; +}; + + +struct s3c2440_clock_power { + volatile unsigned int LOCKTIME; + volatile unsigned int MPLLCON; + volatile unsigned int UPLLCON; + volatile unsigned int CLKCON; + volatile unsigned int CLKSLOW; + volatile unsigned int CLKDIVN; + volatile unsigned int CAMDIVN; +}; + + +/* LCD CONTROLLER (see manual chapter 15) */ +struct s3c2440_lcd { + volatile unsigned int LCDCON1; + volatile unsigned int LCDCON2; + volatile unsigned int LCDCON3; + volatile unsigned int LCDCON4; + volatile unsigned int LCDCON5; + volatile unsigned int LCDSADDR1; + volatile unsigned int LCDSADDR2; + volatile unsigned int LCDSADDR3; + volatile unsigned int REDLUT; + volatile unsigned int GREENLUT; + volatile unsigned int BLUELUT; + volatile unsigned int res[8]; + volatile unsigned int DITHMODE; + volatile unsigned int TPAL; + volatile unsigned int LCDINTPND; + volatile unsigned int LCDSRCPND; + volatile unsigned int LCDINTMSK; + volatile unsigned int TCONSEL; +}; + + +/* NAND FLASH (see S3C2440 manual chapter 6) */ +struct s3c2440_nand { + volatile unsigned int NFCONF; + volatile unsigned int NFCONT; + volatile unsigned int NFCMD; + volatile unsigned int NFADDR; + volatile unsigned int NFDATA; + volatile unsigned int NFMECCD0; + volatile unsigned int NFMECCD1; + volatile unsigned int NFSECCD; + volatile unsigned int NFSTAT; + volatile unsigned int NFESTAT0; + volatile unsigned int NFESTAT1; + volatile unsigned int NFMECC0; + volatile unsigned int NFMECC1; + volatile unsigned int NFSECC; + volatile unsigned int NFSBLK; + volatile unsigned int NFEBLK; +}; + + +/* UART (see manual chapter 11) */ +struct s3c2440_uart { + volatile unsigned int ULCON; + volatile unsigned int UCON; + volatile unsigned int UFCON; + volatile unsigned int UMCON; + volatile unsigned int UTRSTAT; + volatile unsigned int UERSTAT; + volatile unsigned int UFSTAT; + volatile unsigned int UMSTAT; +#ifdef __BIG_ENDIAN + volatile unsigned char res1[3]; + volatile unsigned char UTXH; + volatile unsigned char res2[3]; + volatile unsigned char URXH; +#else /* Little Endian */ + volatile unsigned char UTXH; + volatile unsigned char res1[3]; + volatile unsigned char URXH; + volatile unsigned char res2[3]; +#endif + volatile unsigned int UBRDIV; +}; + + +/* PWM TIMER (see manual chapter 10) */ +struct s3c2440_timer { + volatile unsigned int TCNTB; + volatile unsigned int TCMPB; + volatile unsigned int TCNTO; +}; + +struct s3c2440_timers { + volatile unsigned int TCFG0; + volatile unsigned int TCFG1; + volatile unsigned int TCON; + struct s3c2440_timer ch[4]; + volatile unsigned int TCNTB4; + volatile unsigned int TCNTO4; +}; + + +/* USB DEVICE (see manual chapter 13) */ +struct s3c2440_usb_dev_fifos { +#ifdef __BIG_ENDIAN + volatile unsigned char res[3]; + volatile unsigned char EP_FIFO_REG; +#else /* little endian */ + volatile unsigned char EP_FIFO_REG; + volatile unsigned char res[3]; +#endif +}; + +struct s3c2440_usb_dev_dmas { +#ifdef __BIG_ENDIAN + volatile unsigned char res1[3]; + volatile unsigned char EP_DMA_CON; + volatile unsigned char res2[3]; + volatile unsigned char EP_DMA_UNIT; + volatile unsigned char res3[3]; + volatile unsigned char EP_DMA_FIFO; + volatile unsigned char res4[3]; + volatile unsigned char EP_DMA_TTC_L; + volatile unsigned char res5[3]; + volatile unsigned char EP_DMA_TTC_M; + volatile unsigned char res6[3]; + volatile unsigned char EP_DMA_TTC_H; +#else /* little endian */ + volatile unsigned char EP_DMA_CON; + volatile unsigned char res1[3]; + volatile unsigned char EP_DMA_UNIT; + volatile unsigned char res2[3]; + volatile unsigned char EP_DMA_FIFO; + volatile unsigned char res3[3]; + volatile unsigned char EP_DMA_TTC_L; + volatile unsigned char res4[3]; + volatile unsigned char EP_DMA_TTC_M; + volatile unsigned char res5[3]; + volatile unsigned char EP_DMA_TTC_H; + volatile unsigned char res6[3]; +#endif +}; + +struct s3c2440_usb_device { +#ifdef __BIG_ENDIAN + volatile unsigned char res1[3]; + volatile unsigned char FUNC_ADDR_REG; + volatile unsigned char res2[3]; + volatile unsigned char PWR_REG; + volatile unsigned char res3[3]; + volatile unsigned char EP_INT_REG; + volatile unsigned char res4[15]; + volatile unsigned char USB_INT_REG; + volatile unsigned char res5[3]; + volatile unsigned char EP_INT_EN_REG; + volatile unsigned char res6[15]; + volatile unsigned char USB_INT_EN_REG; + volatile unsigned char res7[3]; + volatile unsigned char FRAME_NUM1_REG; + volatile unsigned char res8[3]; + volatile unsigned char FRAME_NUM2_REG; + volatile unsigned char res9[3]; + volatile unsigned char INDEX_REG; + volatile unsigned char res10[7]; + volatile unsigned char MAXP_REG; + volatile unsigned char res11[3]; + volatile unsigned char EP0_CSR_IN_CSR1_REG; + volatile unsigned char res12[3]; + volatile unsigned char IN_CSR2_REG; + volatile unsigned char res13[7]; + volatile unsigned char OUT_CSR1_REG; + volatile unsigned char res14[3]; + volatile unsigned char OUT_CSR2_REG; + volatile unsigned char res15[3]; + volatile unsigned char OUT_FIFO_CNT1_REG; + volatile unsigned char res16[3]; + volatile unsigned char OUT_FIFO_CNT2_REG; +#else /* little endian */ + volatile unsigned char FUNC_ADDR_REG; + volatile unsigned char res1[3]; + volatile unsigned char PWR_REG; + volatile unsigned char res2[3]; + volatile unsigned char EP_INT_REG; + volatile unsigned char res3[15]; + volatile unsigned char USB_INT_REG; + volatile unsigned char res4[3]; + volatile unsigned char EP_INT_EN_REG; + volatile unsigned char res5[15]; + volatile unsigned char USB_INT_EN_REG; + volatile unsigned char res6[3]; + volatile unsigned char FRAME_NUM1_REG; + volatile unsigned char res7[3]; + volatile unsigned char FRAME_NUM2_REG; + volatile unsigned char res8[3]; + volatile unsigned char INDEX_REG; + volatile unsigned char res9[7]; + volatile unsigned char MAXP_REG; + volatile unsigned char res10[7]; + volatile unsigned char EP0_CSR_IN_CSR1_REG; + volatile unsigned char res11[3]; + volatile unsigned char IN_CSR2_REG; + volatile unsigned char res12[3]; + volatile unsigned char OUT_CSR1_REG; + volatile unsigned char res13[7]; + volatile unsigned char OUT_CSR2_REG; + volatile unsigned char res14[3]; + volatile unsigned char OUT_FIFO_CNT1_REG; + volatile unsigned char res15[3]; + volatile unsigned char OUT_FIFO_CNT2_REG; + volatile unsigned char res16[3]; +#endif /* __BIG_ENDIAN */ + struct s3c2440_usb_dev_fifos fifo[5]; + struct s3c2440_usb_dev_dmas dma[5]; +}; + + +/* WATCH DOG TIMER (see manual chapter 18) */ +struct s3c2440_watchdog { + volatile unsigned int WTCON; + volatile unsigned int WTDAT; + volatile unsigned int WTCNT; +}; + + +/* IIC (see manual chapter 20) */ +struct s3c2440_i2c { + volatile unsigned int IICCON; + volatile unsigned int IICSTAT; + volatile unsigned int IICADD; + volatile unsigned int IICDS; +}; + + +/* IIS (see manual chapter 21) */ +struct s3c2440_i2s { +#ifdef __BIG_ENDIAN + volatile unsigned short res1; + volatile unsigned short IISCON; + volatile unsigned short res2; + volatile unsigned short IISMOD; + volatile unsigned short res3; + volatile unsigned short IISPSR; + volatile unsigned short res4; + volatile unsigned short IISFCON; + volatile unsigned short res5; + volatile unsigned short IISFIFO; +#else /* little endian */ + volatile unsigned short IISCON; + volatile unsigned short res1; + volatile unsigned short IISMOD; + volatile unsigned short res2; + volatile unsigned short IISPSR; + volatile unsigned short res3; + volatile unsigned short IISFCON; + volatile unsigned short res4; + volatile unsigned short IISFIFO; + volatile unsigned short res5; +#endif +}; + + +/* I/O PORT (see manual chapter 9) */ +struct s3c2440_gpio { + volatile unsigned int GPACON; + volatile unsigned int GPADAT; + volatile unsigned int res1[2]; + volatile unsigned int GPBCON; + volatile unsigned int GPBDAT; + volatile unsigned int GPBUP; + volatile unsigned int res2; + volatile unsigned int GPCCON; + volatile unsigned int GPCDAT; + volatile unsigned int GPCUP; + volatile unsigned int res3; + volatile unsigned int GPDCON; + volatile unsigned int GPDDAT; + volatile unsigned int GPDUP; + volatile unsigned int res4; + volatile unsigned int GPECON; + volatile unsigned int GPEDAT; + volatile unsigned int GPEUP; + volatile unsigned int res5; + volatile unsigned int GPFCON; + volatile unsigned int GPFDAT; + volatile unsigned int GPFUP; + volatile unsigned int res6; + volatile unsigned int GPGCON; + volatile unsigned int GPGDAT; + volatile unsigned int GPGUP; + volatile unsigned int res7; + volatile unsigned int GPHCON; + volatile unsigned int GPHDAT; + volatile unsigned int GPHUP; + volatile unsigned int res8; + + volatile unsigned int MISCCR; + volatile unsigned int DCLKCON; + volatile unsigned int EXTINT0; + volatile unsigned int EXTINT1; + volatile unsigned int EXTINT2; + volatile unsigned int EINTFLT0; + volatile unsigned int EINTFLT1; + volatile unsigned int EINTFLT2; + volatile unsigned int EINTFLT3; + volatile unsigned int EINTMASK; + volatile unsigned int EINTPEND; + volatile unsigned int GSTATUS0; + volatile unsigned int GSTATUS1; + volatile unsigned int GSTATUS2; + volatile unsigned int GSTATUS3; + volatile unsigned int GSTATUS4; +}; + + +/* RTC (see manual chapter 17) */ +struct s3c2440_rtc { +#ifdef __BIG_ENDIAN + volatile unsigned char res1[67]; + volatile unsigned char RTCCON; + volatile unsigned char res2[3]; + volatile unsigned char TICNT; + volatile unsigned char res3[11]; + volatile unsigned char RTCALM; + volatile unsigned char res4[3]; + volatile unsigned char ALMSEC; + volatile unsigned char res5[3]; + volatile unsigned char ALMMIN; + volatile unsigned char res6[3]; + volatile unsigned char ALMHOUR; + volatile unsigned char res7[3]; + volatile unsigned char ALMDATE; + volatile unsigned char res8[3]; + volatile unsigned char ALMMON; + volatile unsigned char res9[3]; + volatile unsigned char ALMYEAR; + volatile unsigned char res10[3]; + volatile unsigned char RTCRST; + volatile unsigned char res11[3]; + volatile unsigned char BCDSEC; + volatile unsigned char res12[3]; + volatile unsigned char BCDMIN; + volatile unsigned char res13[3]; + volatile unsigned char BCDHOUR; + volatile unsigned char res14[3]; + volatile unsigned char BCDDATE; + volatile unsigned char res15[3]; + volatile unsigned char BCDDAY; + volatile unsigned char res16[3]; + volatile unsigned char BCDMON; + volatile unsigned char res17[3]; + volatile unsigned char BCDYEAR; +#else /* little endian */ + volatile unsigned char res0[64]; + volatile unsigned char RTCCON; + volatile unsigned char res1[3]; + volatile unsigned char TICNT; + volatile unsigned char res2[11]; + volatile unsigned char RTCALM; + volatile unsigned char res3[3]; + volatile unsigned char ALMSEC; + volatile unsigned char res4[3]; + volatile unsigned char ALMMIN; + volatile unsigned char res5[3]; + volatile unsigned char ALMHOUR; + volatile unsigned char res6[3]; + volatile unsigned char ALMDATE; + volatile unsigned char res7[3]; + volatile unsigned char ALMMON; + volatile unsigned char res8[3]; + volatile unsigned char ALMYEAR; + volatile unsigned char res9[3]; + volatile unsigned char RTCRST; + volatile unsigned char res10[3]; + volatile unsigned char BCDSEC; + volatile unsigned char res11[3]; + volatile unsigned char BCDMIN; + volatile unsigned char res12[3]; + volatile unsigned char BCDHOUR; + volatile unsigned char res13[3]; + volatile unsigned char BCDDATE; + volatile unsigned char res14[3]; + volatile unsigned char BCDDAY; + volatile unsigned char res15[3]; + volatile unsigned char BCDMON; + volatile unsigned char res16[3]; + volatile unsigned char BCDYEAR; + volatile unsigned char res17[3]; +#endif +}; + + +/* ADC (see manual chapter 16) */ +struct s3c2440_adc { + volatile unsigned int ADCCON; + volatile unsigned int ADCTSC; + volatile unsigned int ADCDLY; + volatile unsigned int ADCDAT0; + volatile unsigned int ADCDAT1; + volatile unsigned int ADCUPDN; +}; + + +/* SPI (see manual chapter 22) */ +struct s3c2440_spi_channel { + volatile unsigned char SPCON; + volatile unsigned char res1[3]; + volatile unsigned char SPSTA; + volatile unsigned char res2[3]; + volatile unsigned char SPPIN; + volatile unsigned char res3[3]; + volatile unsigned char SPPRE; + volatile unsigned char res4[3]; + volatile unsigned char SPTDAT; + volatile unsigned char res5[3]; + volatile unsigned char SPRDAT; + volatile unsigned char res6[3]; + volatile unsigned char res7[16]; +}; + +struct s3c2440_spi { + struct s3c2440_spi_channel ch[S3C2440_SPI_CHANNELS]; +}; + + +struct s3c2440_sdi { + volatile unsigned int SDICON; + volatile unsigned int SDIPRE; + volatile unsigned int SDICARG; + volatile unsigned int SDICCON; + volatile unsigned int SDICSTA; + volatile unsigned int SDIRSP0; + volatile unsigned int SDIRSP1; + volatile unsigned int SDIRSP2; + volatile unsigned int SDIRSP3; + volatile unsigned int SDIDTIMER; + volatile unsigned int SDIBSIZE; + volatile unsigned int SDIDCON; + volatile unsigned int SDIDCNT; + volatile unsigned int SDIDSTA; + volatile unsigned int SDIFSTA; +#ifdef __BIG_ENDIAN + volatile unsigned char res[3]; + volatile unsigned char SDIDAT; +#else + volatile unsigned char SDIDAT; + volatile unsigned char res[3]; +#endif + volatile unsigned int SDIIMSK; +}; + + + +/* S3C2440 only supports 512 Byte HW ECC */ +#define S3C2440_ECCSIZE 512 +#define S3C2440_ECCBYTES 3 + +enum s3c2440_uarts_nr { + S3C2440_UART0 = 0, + S3C2440_UART1 = 1, + S3C2440_UART2 = 2 +}; + +/* S3C2440 device base addresses */ +#define S3C2440_MEMCTL_BASE 0x48000000 +#define S3C2440_USB_HOST_BASE 0x49000000 +#define S3C2440_INTERRUPT_BASE 0x4A000000 +#define S3C2440_DMA_BASE 0x4B000000 +#define S3C2440_CLOCK_POWER_BASE 0x4C000000 +#define S3C2440_LCD_BASE 0x4D000000 +#define S3C2440_NAND_BASE 0x4E000000 +#define S3C2440_UART_BASE 0x50000000 +#define S3C2440_TIMER_BASE 0x51000000 +#define S3C2440_USB_DEVICE_BASE 0x52000140 +#define S3C2440_WATCHDOG_BASE 0x53000000 +#define S3C2440_I2C_BASE 0x54000000 +#define S3C2440_I2S_BASE 0x55000000 +#define S3C2440_GPIO_BASE 0x56000000 +#define S3C2440_RTC_BASE 0x57000000 +#define S3C2440_ADC_BASE 0x58000000 +#define S3C2440_SPI_BASE 0x59000000 +#define S3C2440_SDI_BASE 0x5A000000 + + +static inline struct s3c2440_memctl *s3c2440_get_base_memctl(void) +{ + return (struct s3c2440_memctl *)S3C2440_MEMCTL_BASE; +} + +static inline struct s3c2440_usb_host *s3c2440_get_base_usb_host(void) +{ + return (struct s3c2440_usb_host *)S3C2440_USB_HOST_BASE; +} + +static inline struct s3c2440_interrupt *s3c2440_get_base_interrupt(void) +{ + return (struct s3c2440_interrupt *)S3C2440_INTERRUPT_BASE; +} + +static inline struct s3c2440_dmas *s3c2440_get_base_dmas(void) +{ + return (struct s3c2440_dmas *)S3C2440_DMA_BASE; +} + +static inline struct s3c2440_clock_power *s3c2440_get_base_clock_power(void) +{ + return (struct s3c2440_clock_power *)S3C2440_CLOCK_POWER_BASE; +} + +static inline struct s3c2440_lcd *s3c2440_get_base_lcd(void) +{ + return (struct s3c2440_lcd *)S3C2440_LCD_BASE; +} + +static inline struct s3c2440_nand *s3c2440_get_base_nand(void) +{ + return (struct s3c2440_nand *)S3C2440_NAND_BASE; +} + +static inline struct s3c2440_uart *s3c2440_get_base_uart(enum s3c2440_uarts_nr n) +{ + return (struct s3c2440_uart *)(S3C2440_UART_BASE + (n * 0x4000)); +} + +static inline struct s3c2440_timers *s3c2440_get_base_timers(void) +{ + return (struct s3c2440_timers *)S3C2440_TIMER_BASE; +} + +static inline struct s3c2440_usb_device *s3c2440_get_base_usb_device(void) +{ + return (struct s3c2440_usb_device *)S3C2440_USB_DEVICE_BASE; +} + +static inline struct s3c2440_watchdog *s3c2440_get_base_watchdog(void) +{ + return (struct s3c2440_watchdog *)S3C2440_WATCHDOG_BASE; +} + +static inline struct s3c2440_i2c *s3c2440_get_base_i2c(void) +{ + return (struct s3c2440_i2c *)S3C2440_I2C_BASE; +} + +static inline struct s3c2440_i2s *s3c2440_get_base_i2s(void) +{ + return (struct s3c2440_i2s *)S3C2440_I2S_BASE; +} + +static inline struct s3c2440_gpio *s3c2440_get_base_gpio(void) +{ + return (struct s3c2440_gpio *)S3C2440_GPIO_BASE; +} + +static inline struct s3c2440_rtc *s3c2440_get_base_rtc(void) +{ + return (struct s3c2440_rtc *)S3C2440_RTC_BASE; +} + +static inline struct s3c2440_adc *s3c2440_get_base_adc(void) +{ + return (struct s3c2440_adc *)S3C2440_ADC_BASE; +} + +static inline struct s3c2440_spi *s3c2440_get_base_spi(void) +{ + return (struct s3c2440_spi *)S3C2440_SPI_BASE; +} + +static inline struct s3c2440_sdi *s3c2440_get_base_sdi(void) +{ + return (struct s3c2440_sdi *)S3C2440_SDI_BASE; +} + +#endif /*__S3C2440_H__*/ diff --git a/linux-bsp/asm-study/yaffs2/bsp/s3c_board.c b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.c new file mode 100644 index 0000000..8007477 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.c @@ -0,0 +1,213 @@ +#include "s3c_board.h" +#include "s3c2440.h" + +unsigned int s3c2440_get_fclk(void) +{ + struct s3c2440_clock_power *clk_power = s3c2440_get_base_clock_power(); + unsigned int r, m, p, s; + + r = clk_power->MPLLCON; + + m = ((r & 0xFF000) >> 12) + 8; + p = ((r & 0x003F0) >> 4) + 2; + s = r & 0x3; + + return (SYS_CLK_FREQ * m * 2) / (p << s); +} + +unsigned int s3c2440_get_hclk(void) +{ + struct s3c2440_clock_power * const clk_power = s3c2440_get_base_clock_power(); + unsigned int fclk = s3c2440_get_fclk(); + + if (clk_power->CLKDIVN & 0x6) + { + if ((clk_power->CLKDIVN & 0x6)==2) + return fclk/2; + if ((clk_power->CLKDIVN & 0x6)==6) + return (clk_power->CAMDIVN & 0x100) ? fclk/6 : fclk/3; + if ((clk_power->CLKDIVN & 0x6)==4) + return (clk_power->CAMDIVN & 0x200) ? fclk/8 : fclk/4; + return fclk; + } + + return fclk; +} + +unsigned int s3c2440_get_pclk(void) +{ + struct s3c2440_clock_power * const clk_power = s3c2440_get_base_clock_power(); + unsigned int hclk = s3c2440_get_hclk(); + + return (clk_power->CLKDIVN & 0x1) ? hclk/2 : hclk; +} + +unsigned int s3c2440_get_uclk(void) +{ + struct s3c2440_clock_power *clk_power = s3c2440_get_base_clock_power(); + unsigned int r, m, p, s; + + r = clk_power->UPLLCON; + + m = ((r & 0xFF000) >> 12) + 8; + p = ((r & 0x003F0) >> 4) + 2; + s = r & 0x3; + + return (SYS_CLK_FREQ * m) / (p << s); +} + +void s3c2440_set_baudrate(unsigned int baudrate, int index) +{ + struct s3c2440_uart *uart = s3c2440_get_base_uart(index); + unsigned int reg = 0; + int i; + reg = s3c2440_get_pclk() / (16 * baudrate) - 1; + + uart->UBRDIV = reg; + for (i = 0; i < 100; i++); +} + +int s3c2440_serial_init(unsigned int baudrate, int index) +{ + struct s3c2440_uart *uart = s3c2440_get_base_uart(index); + + /* FIFO enable, Tx/Rx FIFO clear */ + uart->UFCON = 0x07; + uart->UMCON = 0x0; + + /* Normal,No parity,1 stop,8 bit */ + uart->ULCON = 0x3; + /* + * tx=level,rx=edge,disable timeout int.,enable rx error int., + * normal,interrupt or polling + */ + uart->UCON = (1<<8) | (1<<2) | (1<<0); + +// uart->UMCON = 0x1; /* RTS up */ + + s3c2440_set_baudrate(baudrate, index); + + return (0); +} + +int s3c2440_serail_set_afc(int enable, int index) +{ + if (index != S3C2440_UART0 || index != S3C2440_UART1) + return -1; + + struct s3c2440_uart *uart = s3c2440_get_base_uart(index); + if (enable) { + uart->UMCON = (1<<4); + } else { + uart->UMCON = 0; + uart->UMCON = 0; + uart->UMCON = 0; + uart->UMCON = 1; + } + + return 0; +} + +/* + * Read a single byte from the serial port. Returns 1 on success, 0 + * otherwise. When the function is succesfull, the character read is + * written into its argument c. + */ +int s3c2440_serial_getc (int index) +{ + struct s3c2440_uart *uart = s3c2440_get_base_uart(index); + + /* wait for character to arrive */ + //while (!(uart->UTRSTAT & 0x1)); + while(!(uart->UFSTAT & 0x1F)); + + return uart->URXH & 0xff; +} + +#if 0 +static int hwflow = 0; /* turned off by default */ +int hwflow_onoff(int on) +{ + switch(on) { + case 0: + default: + break; /* return current */ + case 1: + hwflow = 1; /* turn on */ + break; + case -1: + hwflow = 0; /* turn off */ + break; + } + return hwflow; +} +#endif + +#if 0 +static int be_quiet = 0; +void disable_putc(void) +{ + be_quiet = 1; +} + +void enable_putc(void) +{ + be_quiet = 0; +} +#endif + + +/* + * Output a single byte to the serial port. + */ +void s3c2440_serial_putc (char c, int index) +{ + struct s3c2440_uart *uart = s3c2440_get_base_uart(index); + + /* wait for room in the tx FIFO */ + //while ((!(uart->UTRSTAT & 0x2))); + while (uart->UFSTAT & (1<<14)); + uart->UTXH = c; +} + + +void s3c2440_serial_puts(const char *s, int index) +{ + while (*s) + { + if (*s == '\n') /* If \n, also do \r */ + s3c2440_serial_putc('\r', index); + s3c2440_serial_putc (*s++, index); + } +} + + +void s3c2440_interrupt_enable(unsigned int mask) +{ + mask = ~mask; + struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt(); + interrupt->INTMSK &= mask; +} + +void s3c2440_interrupt_disable(unsigned int mask) +{ + struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt(); + interrupt->INTMSK |= mask; +} + +void s3c2440_sub_interrupt_enable(unsigned int mask) +{ + mask = ~mask; + struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt(); + interrupt->INTSUBMSK &= mask; +} + +void s3c2440_sub_interrupt_disable(unsigned int mask) +{ + struct s3c2440_interrupt *interrupt = s3c2440_get_base_interrupt(); + interrupt->INTSUBMSK |= mask; +} + + + + diff --git a/linux-bsp/asm-study/yaffs2/bsp/s3c_board.h b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.h new file mode 100644 index 0000000..7b979a1 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/bsp/s3c_board.h @@ -0,0 +1,34 @@ +#ifndef __S3C_BOARD_H__ +#define __S3C_BOARD_H__ + +#include "s3c2440.h" + +#define SYS_CLK_FREQ 12000000 +#define CONSOLE_SERIAL S3C2440_UART0 +#define CONSOLE_BAUDRATE 115200 + +unsigned int s3c2440_get_fclk(void); +unsigned int s3c2440_get_hclk(void); +unsigned int s3c2440_get_pclk(void); +unsigned int s3c2440_get_uclk(void); + +void s3c2440_set_baudrate(unsigned int baudrate, int index); +int s3c2440_serial_init(unsigned int baudrate, int index); +int s3c2440_serail_set_afc(int enable, int index); +int s3c2440_serial_getc (int index); +void s3c2440_serial_putc (char ch, int index); +int s3c2440_serial_tstc(int index); +void s3c2440_serial_puts(const char *s, int index); + +#define console_serial_init() s3c2440_serial_init(CONSOLE_BAUDRATE, CONSOLE_SERIAL) +#define console_serial_getc() s3c2440_serial_getc(CONSOLE_SERIAL) +#define console_serial_tstc() s3c2440_serial_tstc(CONSOLE_SERIAL) +#define console_serial_putc(c) s3c2440_serial_putc(c, CONSOLE_SERIAL) +#define console_serial_puts(s) s3c2440_serial_puts(s, CONSOLE_SERIAL) + +void s3c2440_interrupt_enable(unsigned int mask); +void s3c2440_interrupt_disable(unsigned int mask); +void s3c2440_sub_interrupt_enable(unsigned int mask); +void s3c2440_sub_interrupt_disable(unsigned int mask); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/common/dlmalloc.c b/linux-bsp/asm-study/yaffs2/common/dlmalloc.c new file mode 100644 index 0000000..8ba1694 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/dlmalloc.c @@ -0,0 +1,3320 @@ +#include <stdio.h> +#include <string.h> +#include <malloc.h> + +#define DEBUG 1 + +#if 0 /* Moved to malloc.h */ +/* ---------- To make a malloc.h, start cutting here ------------ */ + +/* + A version of malloc/free/realloc written by Doug Lea and released to the + public domain. Send questions/comments/complaints/performance data + to dl@cs.oswego.edu + +* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://g.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Why use this malloc? + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and tunable. + Consistent balance across these factors results in a good general-purpose + allocator. For a high-level description, see + http://g.oswego.edu/dl/html/malloc.html + +* Synopsis of public routines + + (Much fuller descriptions are contained in the program documentation below.) + + malloc(size_t n); + Return a pointer to a newly allocated chunk of at least n bytes, or null + if no space is available. + free(Void_t* p); + Release the chunk of memory pointed to by p, or no effect if p is null. + realloc(Void_t* p, size_t n); + Return a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. The returned pointer may or may not be + the same as p. If p is null, equivalent to malloc. Unless the + #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + memalign(size_t alignment, size_t n); + Return a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument, which must be a power of + two. + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system (or as near to this as can be figured out from + all the includes/defines below.) + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + calloc(size_t unit, size_t quantity); + Returns a pointer to quantity * unit bytes, with all locations + set to zero. + cfree(Void_t* p); + Equivalent to free(p). + malloc_trim(size_t pad); + Release all but pad bytes of freed top-most memory back + to the system. Return 1 if successful, else 0. + malloc_usable_size(Void_t* p); + Report the number usable allocated bytes associated with allocated + chunk p. This may or may not report more bytes than were requested, + due to alignment and minimum size constraints. + malloc_stats(); + Prints brief summary statistics. + mallinfo() + Returns (by copy) a struct containing various summary statistics. + mallopt(int parameter_number, int parameter_value) + Changes one of the tunable parameters described below. Returns + 1 if successful in changing the parameter, else 0. + +* Vital statistics: + + Alignment: 8-byte + 8 byte alignment is currently hardwired into the design. This + seems to suffice for all current machines and C compilers. + + Assumed pointer representation: 4 or 8 bytes + Code for 8-byte pointers is untested by me but has worked + reliably by Wolfram Gloger, who contributed most of the + changes supporting this. + + Assumed size_t representation: 4 or 8 bytes + Note that size_t is allowed to be 4 bytes even if pointers are 8. + + Minimum overhead per allocated chunk: 4 or 8 bytes + Each malloced chunk has a hidden overhead of 4 bytes holding size + and status information. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) + 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) + + When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte + ptrs but 4 byte size) or 24 (for 8/8) additional bytes are + needed; 4 (8) for a trailing size field + and 8 (16) bytes for free list pointers. Thus, the minimum + allocatable size is 16/24/32 bytes. + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + + Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes + 8-byte size_t: 2^63 - 16 bytes + + It is assumed that (possibly signed) size_t bit values suffice to + represent chunk sizes. `Possibly signed' is due to the fact + that `size_t' may be defined on a system as either a signed or + an unsigned type. To be conservative, values that would appear + as negative numbers are avoided. + Requests for sizes with a negative sign bit when the request + size is treaded as a long will return null. + + Maximum overhead wastage per allocated chunk: normally 15 bytes + + Alignnment demands, plus the minimum allocatable size restriction + make the normal worst-case wastage 15 bytes (i.e., up to 15 + more bytes will be allocated than were requested in malloc), with + two exceptions: + 1. Because requests for zero bytes allocate non-zero space, + the worst case wastage for a request of zero bytes is 24 bytes. + 2. For requests >= mmap_threshold that are serviced via + mmap(), the worst case wastage is 8 bytes plus the remainder + from a system page (the minimal mmap unit); typically 4096 bytes. + +* Limitations + + Here are some features that are NOT currently supported + + * No user-definable hooks for callbacks and the like. + * No automated mechanism for fully checking that all accesses + to malloced memory stay within their bounds. + * No support for compaction. + +* Synopsis of compile-time options: + + People have reported using previous versions of this malloc on all + versions of Unix, sometimes by tweaking some of the defines + below. It has been tested most extensively on Solaris and + Linux. It is also reported to work on WIN32 platforms. + People have also reported adapting this malloc for use in + stand-alone embedded systems. + + The implementation is in straight, hand-tuned ANSI C. Among other + consequences, it uses a lot of macros. Because of this, to be at + all usable, this code should be compiled using an optimizing compiler + (for example gcc -O2) that can simplify expressions and control + paths. + + __STD_C (default: derived from C compiler defines) + Nonzero if using ANSI-standard C compiler, a C++ compiler, or + a C compiler sufficiently close to ANSI to get away with it. + DEBUG (default: NOT defined) + Define to enable debugging. Adds fairly extensive assertion-based + checking to help track down memory errors, but noticeably slows down + execution. + REALLOC_ZERO_BYTES_FREES (default: NOT defined) + Define this if you think that realloc(p, 0) should be equivalent + to free(p). Otherwise, since malloc returns a unique pointer for + malloc(0), so does realloc(p, 0). + HAVE_MEMCPY (default: defined) + Define if you are not otherwise using ANSI STD C, but still + have memcpy and memset in your C library and want to use them. + Otherwise, simple internal versions are supplied. + USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise) + Define as 1 if you want the C library versions of memset and + memcpy called in realloc and calloc (otherwise macro versions are used). + At least on some platforms, the simple macro versions usually + outperform libc versions. + HAVE_MMAP (default: defined as 1) + Define to non-zero to optionally make malloc() use mmap() to + allocate very large blocks. + HAVE_MREMAP (default: defined as 0 unless Linux libc set) + Define to non-zero to optionally make realloc() use mremap() to + reallocate very large blocks. + malloc_getpagesize (default: derived from system #includes) + Either a constant or routine call returning the system page size. + HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined) + Optionally define if you are on a system with a /usr/include/malloc.h + that declares struct mallinfo. It is not at all necessary to + define this even if you do, but will ensure consistency. + INTERNAL_SIZE_T (default: size_t) + Define to a 32-bit type (probably `unsigned int') if you are on a + 64-bit machine, yet do not want or need to allow malloc requests of + greater than 2^31 to be handled. This saves space, especially for + very small chunks. + INTERNAL_LINUX_C_LIB (default: NOT defined) + Defined only when compiled as part of Linux libc. + Also note that there is some odd internal name-mangling via defines + (for example, internally, `malloc' is named `mALLOc') needed + when compiling in this case. These look funny but don't otherwise + affect anything. + WIN32 (default: undefined) + Define this on MS win (95, nt) platforms to compile in sbrk emulation. + LACKS_UNISTD_H (default: undefined if not WIN32) + Define this if your system does not have a <unistd.h>. + LACKS_SYS_PARAM_H (default: undefined if not WIN32) + Define this if your system does not have a <sys/param.h>. + MORECORE (default: sbrk) + The name of the routine to call to obtain more memory from the system. + MORECORE_FAILURE (default: -1) + The value returned upon failure of MORECORE. + MORECORE_CLEARS (default 1) + true (1) if the routine mapped to MORECORE zeroes out memory (which + holds for sbrk). + DEFAULT_TRIM_THRESHOLD + DEFAULT_TOP_PAD + DEFAULT_MMAP_THRESHOLD + DEFAULT_MMAP_MAX + Default values of tunable parameters (described in detail below) + controlling interaction with host system routines (sbrk, mmap, etc). + These values may also be changed dynamically via mallopt(). The + preset defaults are those that give best performance for typical + programs/systems. + USE_DL_PREFIX (default: undefined) + Prefix all public routines with the string 'dl'. Useful to + quickly avoid procedure declaration conflicts and linker symbol + conflicts with existing memory allocation routines. + + +*/ + + + +/* Preliminaries */ + +#ifndef __STD_C +#ifdef __STDC__ +#define __STD_C 1 +#else +#if __cplusplus +#define __STD_C 1 +#else +#define __STD_C 0 +#endif /*__cplusplus*/ +#endif /*__STDC__*/ +#endif /*__STD_C*/ + +#ifndef Void_t +#if (__STD_C || defined(WIN32)) +#define Void_t void +#else +#define Void_t char +#endif +#endif /*Void_t*/ + +#if __STD_C +#include <stddef.h> /* for size_t */ +#else +#include <sys/types.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stdio.h> /* needed for malloc_stats */ + + +/* + Compile-time options +*/ + + +/* + Debugging: + + Because freed chunks may be overwritten with link fields, this + malloc will often die when freed memory is overwritten by user + programs. This can be very effective (albeit in an annoying way) + in helping track down dangling pointers. + + If you compile with -DDEBUG, a number of assertion checks are + enabled that will catch more memory errors. You probably won't be + able to make much sense of the actual assertion errors, but they + should help you locate incorrectly overwritten memory. The + checking is fairly extensive, and will slow down execution + noticeably. Calling malloc_stats or mallinfo with DEBUG set will + attempt to check every non-mmapped allocated and free chunk in the + course of computing the summmaries. (By nature, mmapped regions + cannot be checked very much automatically.) + + Setting DEBUG may also be helpful if you are trying to modify + this code. The assertions in the check routines spell out in more + detail the assumptions and invariants underlying the algorithms. + +*/ + +/* + INTERNAL_SIZE_T is the word-size used for internal bookkeeping + of chunk sizes. On a 64-bit machine, you can reduce malloc + overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' + at the expense of not being able to handle requests greater than + 2^31. This limitation is hardly ever a concern; you are encouraged + to set this. However, the default version is the same as size_t. +*/ + +#ifndef INTERNAL_SIZE_T +#define INTERNAL_SIZE_T size_t +#endif + +/* + REALLOC_ZERO_BYTES_FREES should be set if a call to + realloc with zero bytes should be the same as a call to free. + Some people think it should. Otherwise, since this malloc + returns a unique pointer for malloc(0), so does realloc(p, 0). +*/ + + +/* #define REALLOC_ZERO_BYTES_FREES */ + + +/* + WIN32 causes an emulation of sbrk to be compiled in + mmap-based options are not currently supported in WIN32. +*/ + +/* #define WIN32 */ +#ifdef WIN32 +#define MORECORE wsbrk +#define HAVE_MMAP 0 + +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H + +/* + Include 'windows.h' to get the necessary declarations for the + Microsoft Visual C++ data structures and routines used in the 'sbrk' + emulation. + + Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft + Visual C++ header files are included. +*/ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + + +/* + HAVE_MEMCPY should be defined if you are not otherwise using + ANSI STD C, but still have memcpy and memset in your C library + and want to use them in calloc and realloc. Otherwise simple + macro versions are defined here. + + USE_MEMCPY should be defined as 1 if you actually want to + have memset and memcpy called. People report that the macro + versions are often enough faster than libc versions on many + systems that it is better to use them. + +*/ + +#define HAVE_MEMCPY + +#ifndef USE_MEMCPY +#ifdef HAVE_MEMCPY +#define USE_MEMCPY 1 +#else +#define USE_MEMCPY 0 +#endif +#endif + +#if (__STD_C || defined(HAVE_MEMCPY)) + +#if __STD_C +void* memset(void*, int, size_t); +void* memcpy(void*, const void*, size_t); +#else +#ifdef WIN32 +/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */ +/* 'windows.h' */ +#else +Void_t* memset(); +Void_t* memcpy(); +#endif +#endif +#endif + +#if USE_MEMCPY + +/* The following macros are only invoked with (2n+1)-multiples of + INTERNAL_SIZE_T units, with a positive integer n. This is exploited + for fast inline execution when n is small. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T mzsz = (nbytes); \ + if(mzsz <= 9*sizeof(mzsz)) { \ + INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \ + if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; \ + if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; \ + if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; }}} \ + *mz++ = 0; \ + *mz++ = 0; \ + *mz = 0; \ + } else memset((charp), 0, mzsz); \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes) \ +do { \ + INTERNAL_SIZE_T mcsz = (nbytes); \ + if(mcsz <= 9*sizeof(mcsz)) { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \ + if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; }}} \ + *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + *mcdst = *mcsrc ; \ + } else memcpy(dest, src, mcsz); \ +} while(0) + +#else /* !USE_MEMCPY */ + +/* Use Duff's device for good zeroing/copying performance. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mzp++ = 0; \ + case 7: *mzp++ = 0; \ + case 6: *mzp++ = 0; \ + case 5: *mzp++ = 0; \ + case 4: *mzp++ = 0; \ + case 3: *mzp++ = 0; \ + case 2: *mzp++ = 0; \ + case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes) \ +do { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mcdst++ = *mcsrc++; \ + case 7: *mcdst++ = *mcsrc++; \ + case 6: *mcdst++ = *mcsrc++; \ + case 5: *mcdst++ = *mcsrc++; \ + case 4: *mcdst++ = *mcsrc++; \ + case 3: *mcdst++ = *mcsrc++; \ + case 2: *mcdst++ = *mcsrc++; \ + case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#endif + + +/* + Define HAVE_MMAP to optionally make malloc() use mmap() to + allocate very large blocks. These will be returned to the + operating system immediately after a free(). +*/ + +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif + +/* + Define HAVE_MREMAP to make realloc() use mremap() to re-allocate + large blocks. This is currently only possible on Linux with + kernel versions newer than 1.3.77. +*/ + +#ifndef HAVE_MREMAP +#ifdef INTERNAL_LINUX_C_LIB +#define HAVE_MREMAP 1 +#else +#define HAVE_MREMAP 0 +#endif +#endif + +#if HAVE_MMAP + +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + +#endif /* HAVE_MMAP */ + +/* + Access to system page size. To the extent possible, this malloc + manages memory from the system in page-size units. + + The following mechanics for getpagesize were adapted from + bsd/gnu getpagesize.h +*/ + +#ifndef LACKS_UNISTD_H +# include <unistd.h> +#endif + +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 +# define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */ +# else +# ifndef LACKS_SYS_PARAM_H +# include <sys/param.h> +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else +# define malloc_getpagesize (4096) /* just guess */ +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif + + +/* + + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing the same kind of + information you can get from malloc_stats. It should work on + any SVID/XPG compliant system that has a /usr/include/malloc.h + defining struct mallinfo. (If you'd like to install such a thing + yourself, cut out the preliminary declarations as described above + and below and save them in a malloc.h file. But there's no + compelling reason to bother to do this.) + + The main declaration needed is the mallinfo struct that is returned + (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a + bunch of fields, most of which are not even meaningful in this + version of malloc. Some of these fields are are instead filled by + mallinfo() with other numbers that might possibly be of interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else an SVID2/XPG2 compliant + version is declared below. These must be precisely the same for + mallinfo() to work. + +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#if HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else + +/* SVID2/XPG mallinfo structure */ + +struct mallinfo { + int arena; /* total space allocated from system */ + int ordblks; /* number of non-inuse chunks */ + int smblks; /* unused -- always zero */ + int hblks; /* number of mmapped regions */ + int hblkhd; /* total space in mmapped regions */ + int usmblks; /* unused -- always zero */ + int fsmblks; /* unused -- always zero */ + int uordblks; /* total allocated space */ + int fordblks; /* total non-inuse space */ + int keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +/* SVID2/XPG mallopt options */ + +#define M_MXFAST 1 /* UNUSED in this malloc */ +#define M_NLBLKS 2 /* UNUSED in this malloc */ +#define M_GRAIN 3 /* UNUSED in this malloc */ +#define M_KEEP 4 /* UNUSED in this malloc */ + +#endif + +/* mallopt options that actually do something */ + +#define M_TRIM_THRESHOLD -1 +#define M_TOP_PAD -2 +#define M_MMAP_THRESHOLD -3 +#define M_MMAP_MAX -4 + + +#ifndef DEFAULT_TRIM_THRESHOLD +#define DEFAULT_TRIM_THRESHOLD (128 * 1024) +#endif + +/* + M_TRIM_THRESHOLD is the maximum amount of unused top-most memory + to keep before releasing via malloc_trim in free(). + + Automatic trimming is mainly useful in long-lived programs. + Because trimming via sbrk can be slow on some systems, and can + sometimes be wasteful (in cases where programs immediately + afterward allocate more large chunks) the value should be high + enough so that your overall system performance would improve by + releasing. + + The trim threshold and the mmap control parameters (see below) + can be traded off with one another. Trimming and mmapping are + two different ways of releasing unused memory back to the + system. Between these two, it is often possible to keep + system-level demands of a long-lived program down to a bare + minimum. For example, in one test suite of sessions measuring + the XF86 X server on Linux, using a trim threshold of 128K and a + mmap threshold of 192K led to near-minimal long term resource + consumption. + + If you are using this malloc in a long-lived program, it should + pay to experiment with these values. As a rough guide, you + might set to a value close to the average size of a process + (program) running on your system. Releasing this much memory + would allow such a process to run in memory. Generally, it's + worth it to tune for trimming rather tham memory mapping when a + program undergoes phases where several large chunks are + allocated and released in ways that can reuse each other's + storage, perhaps mixed with phases where there are no such + chunks at all. And in well-behaved long-lived programs, + controlling release of large blocks via trimming versus mapping + is usually faster. + + However, in most programs, these parameters serve mainly as + protection against the system-level effects of carrying around + massive amounts of unneeded memory. Since frequent calls to + sbrk, mmap, and munmap otherwise degrade performance, the default + parameters are set to relatively high values that serve only as + safeguards. + + The default trim value is high enough to cause trimming only in + fairly extreme (by current memory consumption standards) cases. + It must be greater than page size to have any useful effect. To + disable trimming completely, you can set to (unsigned long)(-1); + + +*/ + + +#ifndef DEFAULT_TOP_PAD +#define DEFAULT_TOP_PAD (0) +#endif + +/* + M_TOP_PAD is the amount of extra `padding' space to allocate or + retain whenever sbrk is called. It is used in two ways internally: + + * When sbrk is called to extend the top of the arena to satisfy + a new malloc request, this much padding is added to the sbrk + request. + + * When malloc_trim is called automatically from free(), + it is used as the `pad' argument. + + In both cases, the actual amount of padding is rounded + so that the end of the arena is always a system page boundary. + + The main reason for using padding is to avoid calling sbrk so + often. Having even a small pad greatly reduces the likelihood + that nearly every malloc request during program start-up (or + after trimming) will invoke sbrk, which needlessly wastes + time. + + Automatic rounding-up to page-size units is normally sufficient + to avoid measurable overhead, so the default is 0. However, in + systems where sbrk is relatively slow, it can pay to increase + this value, at the expense of carrying around more memory than + the program needs. + +*/ + + +#ifndef DEFAULT_MMAP_THRESHOLD +#define DEFAULT_MMAP_THRESHOLD (128 * 1024) +#endif + +/* + + M_MMAP_THRESHOLD is the request size threshold for using mmap() + to service a request. Requests of at least this size that cannot + be allocated using already-existing space will be serviced via mmap. + (If enough normal freed space already exists it is used instead.) + + Using mmap segregates relatively large chunks of memory so that + they can be individually obtained and released from the host + system. A request serviced through mmap is never reused by any + other request (at least not directly; the system may just so + happen to remap successive requests to the same locations). + + Segregating space in this way has the benefit that mmapped space + can ALWAYS be individually released back to the system, which + helps keep the system level memory demands of a long-lived + program low. Mapped memory can never become `locked' between + other chunks, as can happen with normally allocated chunks, which + menas that even trimming via malloc_trim would not release them. + + However, it has the disadvantages that: + + 1. The space cannot be reclaimed, consolidated, and then + used to service later requests, as happens with normal chunks. + 2. It can lead to more wastage because of mmap page alignment + requirements + 3. It causes malloc performance to be more dependent on host + system memory management support routines which may vary in + implementation quality and may impose arbitrary + limitations. Generally, servicing a request via normal + malloc steps is faster than going through a system's mmap. + + All together, these considerations should lead you to use mmap + only for relatively large requests. + + +*/ + + +#ifndef DEFAULT_MMAP_MAX +#if HAVE_MMAP +#define DEFAULT_MMAP_MAX (64) +#else +#define DEFAULT_MMAP_MAX (0) +#endif +#endif + +/* + M_MMAP_MAX is the maximum number of requests to simultaneously + service using mmap. This parameter exists because: + + 1. Some systems have a limited number of internal tables for + use by mmap. + 2. In most systems, overreliance on mmap can degrade overall + performance. + 3. If a program allocates many large regions, it is probably + better off using normal sbrk-based allocation routines that + can reclaim and reallocate normal heap memory. Using a + small value allows transition into this mode after the + first few allocations. + + Setting to 0 disables all use of mmap. If HAVE_MMAP is not set, + the default value is 0, and attempts to set it to non-zero values + in mallopt will fail. +*/ + + +/* + USE_DL_PREFIX will prefix all public routines with the string 'dl'. + Useful to quickly avoid procedure declaration conflicts and linker + symbol conflicts with existing memory allocation routines. + +*/ + +/* #define USE_DL_PREFIX */ + + +/* + + Special defines for linux libc + + Except when compiled using these special defines for Linux libc + using weak aliases, this malloc is NOT designed to work in + multithreaded applications. No semaphores or other concurrency + control are provided to ensure that multiple malloc or free calls + don't run at the same time, which could be disasterous. A single + semaphore could be used across malloc, realloc, and free (which is + essentially the effect of the linux weak alias approach). It would + be hard to obtain finer granularity. + +*/ + + +#ifdef INTERNAL_LINUX_C_LIB + +#if __STD_C + +Void_t * __default_morecore_init (ptrdiff_t); +Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init; + +#else + +Void_t * __default_morecore_init (); +Void_t *(*__morecore)() = __default_morecore_init; + +#endif + +#define MORECORE (*__morecore) +#define MORECORE_FAILURE 0 +#define MORECORE_CLEARS 1 + +#else /* INTERNAL_LINUX_C_LIB */ + +#if __STD_C +extern Void_t* sbrk(ptrdiff_t); +#else +extern Void_t* sbrk(); +#endif + +#ifndef MORECORE +#define MORECORE sbrk +#endif + +#ifndef MORECORE_FAILURE +#define MORECORE_FAILURE -1 +#endif + +#ifndef MORECORE_CLEARS +#define MORECORE_CLEARS 1 +#endif + +#endif /* INTERNAL_LINUX_C_LIB */ + +#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__) + +#define cALLOc __libc_calloc +#define fREe __libc_free +#define mALLOc __libc_malloc +#define mEMALIGn __libc_memalign +#define rEALLOc __libc_realloc +#define vALLOc __libc_valloc +#define pvALLOc __libc_pvalloc +#define mALLINFo __libc_mallinfo +#define mALLOPt __libc_mallopt + +#pragma weak calloc = __libc_calloc +#pragma weak free = __libc_free +#pragma weak cfree = __libc_free +#pragma weak malloc = __libc_malloc +#pragma weak memalign = __libc_memalign +#pragma weak realloc = __libc_realloc +#pragma weak valloc = __libc_valloc +#pragma weak pvalloc = __libc_pvalloc +#pragma weak mallinfo = __libc_mallinfo +#pragma weak mallopt = __libc_mallopt + +#else + +#ifdef USE_DL_PREFIX +#define cALLOc dlcalloc +#define fREe dlfree +#define mALLOc dlmalloc +#define mEMALIGn dlmemalign +#define rEALLOc dlrealloc +#define vALLOc dlvalloc +#define pvALLOc dlpvalloc +#define mALLINFo dlmallinfo +#define mALLOPt dlmallopt +#else /* USE_DL_PREFIX */ +#define cALLOc calloc +#define fREe free +#define mALLOc malloc +#define mEMALIGn memalign +#define rEALLOc realloc +#define vALLOc valloc +#define pvALLOc pvalloc +#define mALLINFo mallinfo +#define mALLOPt mallopt +#endif /* USE_DL_PREFIX */ + +#endif + +/* Public routines */ + +#if __STD_C + +Void_t* mALLOc(size_t); +void fREe(Void_t*); +Void_t* rEALLOc(Void_t*, size_t); +Void_t* mEMALIGn(size_t, size_t); +Void_t* vALLOc(size_t); +Void_t* pvALLOc(size_t); +Void_t* cALLOc(size_t, size_t); +void cfree(Void_t*); +int malloc_trim(size_t); +size_t malloc_usable_size(Void_t*); +void malloc_stats(); +int mALLOPt(int, int); +struct mallinfo mALLINFo(void); +#else +Void_t* mALLOc(); +void fREe(); +Void_t* rEALLOc(); +Void_t* mEMALIGn(); +Void_t* vALLOc(); +Void_t* pvALLOc(); +Void_t* cALLOc(); +void cfree(); +int malloc_trim(); +size_t malloc_usable_size(); +void malloc_stats(); +int mALLOPt(); +struct mallinfo mALLINFo(); +#endif + + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +/* ---------- To make a malloc.h, end cutting here ------------ */ +#endif /* 0 */ /* Moved to malloc.h */ + +#include <malloc.h> +#ifdef DEBUG +#if __STD_C +static void malloc_update_mallinfo (void); +void malloc_stats (void); +#else +static void malloc_update_mallinfo (); +void malloc_stats(); +#endif +#endif /* DEBUG */ + +/* + Emulation of sbrk for WIN32 + All code within the ifdef WIN32 is untested by me. + + Thanks to Martin Fong and others for supplying this. +*/ + + +#ifdef WIN32 + +#define AlignPage(add) (((add) + (malloc_getpagesize-1)) & \ +~(malloc_getpagesize-1)) +#define AlignPage64K(add) (((add) + (0x10000 - 1)) & ~(0x10000 - 1)) + +/* resrve 64MB to insure large contiguous space */ +#define RESERVED_SIZE (1024*1024*64) +#define NEXT_SIZE (2048*1024) +#define TOP_MEMORY ((unsigned long)2*1024*1024*1024) + +struct GmListElement; +typedef struct GmListElement GmListElement; + +struct GmListElement +{ + GmListElement* next; + void* base; +}; + +static GmListElement* head = 0; +static unsigned int gNextAddress = 0; +static unsigned int gAddressBase = 0; +static unsigned int gAllocatedSize = 0; + +static +GmListElement* makeGmListElement (void* bas) +{ + GmListElement* this; + this = (GmListElement*)(void*)LocalAlloc (0, sizeof (GmListElement)); + assert (this); + if (this) + { + this->base = bas; + this->next = head; + head = this; + } + return this; +} + +void gcleanup () +{ + BOOL rval; + assert ( (head == NULL) || (head->base == (void*)gAddressBase)); + if (gAddressBase && (gNextAddress - gAddressBase)) + { + rval = VirtualFree ((void*)gAddressBase, + gNextAddress - gAddressBase, + MEM_DECOMMIT); + assert (rval); + } + while (head) + { + GmListElement* next = head->next; + rval = VirtualFree (head->base, 0, MEM_RELEASE); + assert (rval); + LocalFree (head); + head = next; + } +} + +static +void* findRegion (void* start_address, unsigned long size) +{ + MEMORY_BASIC_INFORMATION info; + if (size >= TOP_MEMORY) return NULL; + + while ((unsigned long)start_address + size < TOP_MEMORY) + { + VirtualQuery (start_address, &info, sizeof (info)); + if ((info.State == MEM_FREE) && (info.RegionSize >= size)) + return start_address; + else + { + /* Requested region is not available so see if the */ + /* next region is available. Set 'start_address' */ + /* to the next region and call 'VirtualQuery()' */ + /* again. */ + + start_address = (char*)info.BaseAddress + info.RegionSize; + + /* Make sure we start looking for the next region */ + /* on the *next* 64K boundary. Otherwise, even if */ + /* the new region is free according to */ + /* 'VirtualQuery()', the subsequent call to */ + /* 'VirtualAlloc()' (which follows the call to */ + /* this routine in 'wsbrk()') will round *down* */ + /* the requested address to a 64K boundary which */ + /* we already know is an address in the */ + /* unavailable region. Thus, the subsequent call */ + /* to 'VirtualAlloc()' will fail and bring us back */ + /* here, causing us to go into an infinite loop. */ + + start_address = + (void *) AlignPage64K((unsigned long) start_address); + } + } + return NULL; + +} + + +void* wsbrk (long size) +{ + void* tmp; + if (size > 0) + { + if (gAddressBase == 0) + { + gAllocatedSize = max (RESERVED_SIZE, AlignPage (size)); + gNextAddress = gAddressBase = + (unsigned int)VirtualAlloc (NULL, gAllocatedSize, + MEM_RESERVE, PAGE_NOACCESS); + } else if (AlignPage (gNextAddress + size) > (gAddressBase + +gAllocatedSize)) + { + long new_size = max (NEXT_SIZE, AlignPage (size)); + void* new_address = (void*)(gAddressBase+gAllocatedSize); + do + { + new_address = findRegion (new_address, new_size); + + if (new_address == 0) + return (void*)-1; + + gAddressBase = gNextAddress = + (unsigned int)VirtualAlloc (new_address, new_size, + MEM_RESERVE, PAGE_NOACCESS); + /* repeat in case of race condition */ + /* The region that we found has been snagged */ + /* by another thread */ + } + while (gAddressBase == 0); + + assert (new_address == (void*)gAddressBase); + + gAllocatedSize = new_size; + + if (!makeGmListElement ((void*)gAddressBase)) + return (void*)-1; + } + if ((size + gNextAddress) > AlignPage (gNextAddress)) + { + void* res; + res = VirtualAlloc ((void*)AlignPage (gNextAddress), + (size + gNextAddress - + AlignPage (gNextAddress)), + MEM_COMMIT, PAGE_READWRITE); + if (res == 0) + return (void*)-1; + } + tmp = (void*)gNextAddress; + gNextAddress = (unsigned int)tmp + size; + return tmp; + } + else if (size < 0) + { + unsigned int alignedGoal = AlignPage (gNextAddress + size); + /* Trim by releasing the virtual memory */ + if (alignedGoal >= gAddressBase) + { + VirtualFree ((void*)alignedGoal, gNextAddress - alignedGoal, + MEM_DECOMMIT); + gNextAddress = gNextAddress + size; + return (void*)gNextAddress; + } + else + { + VirtualFree ((void*)gAddressBase, gNextAddress - gAddressBase, + MEM_DECOMMIT); + gNextAddress = gAddressBase; + return (void*)-1; + } + } + else + { + return (void*)gNextAddress; + } +} + +#endif + + + +/* + Type declarations +*/ + + +struct malloc_chunk +{ + INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ + INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ + struct malloc_chunk* fd; /* double links -- used only if free. */ + struct malloc_chunk* bk; +} __attribute__((__may_alias__)) ; + +typedef struct malloc_chunk* mchunkptr; + +/* + + malloc_chunk details: + + (The following includes lightly edited explanations by Colin Plumb.) + + Chunks of memory are maintained using a `boundary tag' method as + described in e.g., Knuth or Standish. (See the paper by Paul + Wilson ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a + survey of such techniques.) Sizes of free chunks are stored both + in the front of each chunk and at the end. This makes + consolidating fragmented chunks into bigger chunks very fast. The + size fields also hold bits representing whether chunks are free or + in use. + + An allocated chunk looks like this: + + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk, if allocated | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | User data starts here... . + . . + . (malloc_usable_space() bytes) . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + Where "chunk" is the front of the chunk for the purpose of most of + the malloc code, but "mem" is the pointer that is returned to the + user. "Nextchunk" is the beginning of the next contiguous chunk. + + Chunks always begin on even word boundries, so the mem portion + (which is returned to the user) is also on an even word boundary, and + thus double-word aligned. + + Free chunks are stored in circular doubly-linked lists, and look like this: + + chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Size of previous chunk | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `head:' | Size of chunk, in bytes |P| + mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Forward pointer to next chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Back pointer to previous chunk in list | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Unused space (may be 0 bytes long) . + . . + . | +nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + `foot:' | Size of chunk, in bytes | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + The P (PREV_INUSE) bit, stored in the unused low-order bit of the + chunk size (which is always a multiple of two words), is an in-use + bit for the *previous* chunk. If that bit is *clear*, then the + word before the current chunk size contains the previous chunk + size, and can be used to find the front of the previous chunk. + (The very first chunk allocated always has this bit set, + preventing access to non-existent (or non-owned) memory.) + + Note that the `foot' of the current chunk is actually represented + as the prev_size of the NEXT chunk. (This makes it easier to + deal with alignments etc). + + The two exceptions to all this are + + 1. The special chunk `top', which doesn't bother using the + trailing size field since there is no + next contiguous chunk that would have to index off it. (After + initialization, `top' is forced to always exist. If it would + become less than MINSIZE bytes long, it is replenished via + malloc_extend_top.) + + 2. Chunks allocated via mmap, which have the second-lowest-order + bit (IS_MMAPPED) set in their size fields. Because they are + never merged or traversed from any other chunk, they have no + foot size or inuse information. + + Available chunks are kept in any of several places (all declared below): + + * `av': An array of chunks serving as bin headers for consolidated + chunks. Each bin is doubly linked. The bins are approximately + proportionally (log) spaced. There are a lot of these bins + (128). This may look excessive, but works very well in + practice. All procedures maintain the invariant that no + consolidated chunk physically borders another one. Chunks in + bins are kept in size order, with ties going to the + approximately least recently used chunk. + + The chunks in each bin are maintained in decreasing sorted order by + size. This is irrelevant for the small bins, which all contain + the same-sized chunks, but facilitates best-fit allocation for + larger chunks. (These lists are just sequential. Keeping them in + order almost never requires enough traversal to warrant using + fancier ordered data structures.) Chunks of the same size are + linked with the most recently freed at the front, and allocations + are taken from the back. This results in LRU or FIFO allocation + order, which tends to give each chunk an equal opportunity to be + consolidated with adjacent freed chunks, resulting in larger free + chunks and less fragmentation. + + * `top': The top-most available chunk (i.e., the one bordering the + end of available memory) is treated specially. It is never + included in any bin, is used only if no other chunk is + available, and is released back to the system if it is very + large (see M_TRIM_THRESHOLD). + + * `last_remainder': A bin holding only the remainder of the + most recently split (non-top) chunk. This bin is checked + before other non-fitting chunks, so as to provide better + locality for runs of sequentially allocated chunks. + + * Implicitly, through the host system's memory mapping tables. + If supported, requests greater than a threshold are usually + serviced via calls to mmap, and then later released via munmap. + +*/ + +/* sizes, alignments */ + +#define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) +#define MALLOC_ALIGNMENT (SIZE_SZ + SIZE_SZ) +#define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) +#define MINSIZE (sizeof(struct malloc_chunk)) + +/* conversion from malloc headers to user pointers, and back */ + +#define chunk2mem(p) ((Void_t*)((char*)(p) + 2*SIZE_SZ)) +#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - 2*SIZE_SZ)) + +/* pad request bytes into a usable size */ + +#define request2size(req) \ + (((long)((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) < \ + (long)(MINSIZE + MALLOC_ALIGN_MASK)) ? MINSIZE : \ + (((req) + (SIZE_SZ + MALLOC_ALIGN_MASK)) & ~(MALLOC_ALIGN_MASK))) + +/* Check if m has acceptable alignment */ + +#define aligned_OK(m) (((unsigned long)((m)) & (MALLOC_ALIGN_MASK)) == 0) + + + + +/* + Physical chunk operations +*/ + + +/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */ + +#define PREV_INUSE 0x1 + +/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */ + +#define IS_MMAPPED 0x2 + +/* Bits to mask off when extracting size */ + +#define SIZE_BITS (PREV_INUSE|IS_MMAPPED) + + +/* Ptr to next physical malloc_chunk. */ + +#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->size & ~PREV_INUSE) )) + +/* Ptr to previous physical malloc_chunk */ + +#define prev_chunk(p)\ + ((mchunkptr)( ((char*)(p)) - ((p)->prev_size) )) + + +/* Treat space at ptr + offset as a chunk */ + +#define chunk_at_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) + + + + +/* + Dealing with use bits +*/ + +/* extract p's inuse bit */ + +#define inuse(p)\ +((((mchunkptr)(((char*)(p))+((p)->size & ~PREV_INUSE)))->size) & PREV_INUSE) + +/* extract inuse bit of previous chunk */ + +#define prev_inuse(p) ((p)->size & PREV_INUSE) + +/* check for mmap()'ed chunk */ + +#define chunk_is_mmapped(p) ((p)->size & IS_MMAPPED) + +/* set/clear chunk as in use without otherwise disturbing */ + +#define set_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size |= PREV_INUSE + +#define clear_inuse(p)\ +((mchunkptr)(((char*)(p)) + ((p)->size & ~PREV_INUSE)))->size &= ~(PREV_INUSE) + +/* check/set/clear inuse bits in known places */ + +#define inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size & PREV_INUSE) + +#define set_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size |= PREV_INUSE) + +#define clear_inuse_bit_at_offset(p, s)\ + (((mchunkptr)(((char*)(p)) + (s)))->size &= ~(PREV_INUSE)) + + + + +/* + Dealing with size fields +*/ + +/* Get size, ignoring use bits */ + +#define chunksize(p) ((p)->size & ~(SIZE_BITS)) + +/* Set size at head, without disturbing its use bit */ + +#define set_head_size(p, s) ((p)->size = (((p)->size & PREV_INUSE) | (s))) + +/* Set size/use ignoring previous bits in header */ + +#define set_head(p, s) ((p)->size = (s)) + +/* Set size at footer (only when chunk is not in use) */ + +#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_size = (s)) + + + + + +/* + Bins + + The bins, `av_' are an array of pairs of pointers serving as the + heads of (initially empty) doubly-linked lists of chunks, laid out + in a way so that each pair can be treated as if it were in a + malloc_chunk. (This way, the fd/bk offsets for linking bin heads + and chunks are the same). + + Bins for sizes < 512 bytes contain chunks of all the same size, spaced + 8 bytes apart. Larger bins are approximately logarithmically + spaced. (See the table below.) The `av_' array is never mentioned + directly in the code, but instead via bin access macros. + + Bin layout: + + 64 bins of size 8 + 32 bins of size 64 + 16 bins of size 512 + 8 bins of size 4096 + 4 bins of size 32768 + 2 bins of size 262144 + 1 bin of size what's left + + There is actually a little bit of slop in the numbers in bin_index + for the sake of speed. This makes no difference elsewhere. + + The special chunks `top' and `last_remainder' get their own bins, + (this is implemented via yet more trickery with the av_ array), + although `top' is never properly linked to its bin since it is + always handled specially. + +*/ + +#define NAV 128 /* number of bins */ + +typedef struct malloc_chunk* mbinptr; + +/* access macros */ + +#define bin_at(i) ((mbinptr)((char*)&(av_[2*(i) + 2]) - 2*SIZE_SZ)) +#define next_bin(b) ((mbinptr)((char*)(b) + 2 * sizeof(mbinptr))) +#define prev_bin(b) ((mbinptr)((char*)(b) - 2 * sizeof(mbinptr))) + +/* + The first 2 bins are never indexed. The corresponding av_ cells are instead + used for bookkeeping. This is not to save space, but to simplify + indexing, maintain locality, and avoid some initialization tests. +*/ + +#define top (av_[2]) /* The topmost chunk */ +#define last_remainder (bin_at(1)) /* remainder from last split */ + + +/* + Because top initially points to its own bin with initial + zero size, thus forcing extension on the first malloc request, + we avoid having any special code in malloc to check whether + it even exists yet. But we still need to in malloc_extend_top. +*/ + +#define initial_top ((mchunkptr)(bin_at(0))) + +/* Helper macro to initialize bins */ + +#define IAV(i) bin_at(i), bin_at(i) + +static mbinptr av_[NAV * 2 + 2] = { + NULL, NULL, + IAV(0), IAV(1), IAV(2), IAV(3), IAV(4), IAV(5), IAV(6), IAV(7), + IAV(8), IAV(9), IAV(10), IAV(11), IAV(12), IAV(13), IAV(14), IAV(15), + IAV(16), IAV(17), IAV(18), IAV(19), IAV(20), IAV(21), IAV(22), IAV(23), + IAV(24), IAV(25), IAV(26), IAV(27), IAV(28), IAV(29), IAV(30), IAV(31), + IAV(32), IAV(33), IAV(34), IAV(35), IAV(36), IAV(37), IAV(38), IAV(39), + IAV(40), IAV(41), IAV(42), IAV(43), IAV(44), IAV(45), IAV(46), IAV(47), + IAV(48), IAV(49), IAV(50), IAV(51), IAV(52), IAV(53), IAV(54), IAV(55), + IAV(56), IAV(57), IAV(58), IAV(59), IAV(60), IAV(61), IAV(62), IAV(63), + IAV(64), IAV(65), IAV(66), IAV(67), IAV(68), IAV(69), IAV(70), IAV(71), + IAV(72), IAV(73), IAV(74), IAV(75), IAV(76), IAV(77), IAV(78), IAV(79), + IAV(80), IAV(81), IAV(82), IAV(83), IAV(84), IAV(85), IAV(86), IAV(87), + IAV(88), IAV(89), IAV(90), IAV(91), IAV(92), IAV(93), IAV(94), IAV(95), + IAV(96), IAV(97), IAV(98), IAV(99), IAV(100), IAV(101), IAV(102), IAV(103), + IAV(104), IAV(105), IAV(106), IAV(107), IAV(108), IAV(109), IAV(110), IAV(111), + IAV(112), IAV(113), IAV(114), IAV(115), IAV(116), IAV(117), IAV(118), IAV(119), + IAV(120), IAV(121), IAV(122), IAV(123), IAV(124), IAV(125), IAV(126), IAV(127) +}; + +ulong mem_malloc_start = 0; +ulong mem_malloc_end = 0; +ulong mem_malloc_brk = 0; + +void *sbrk(ptrdiff_t increment) +{ + ulong old = mem_malloc_brk; + ulong new = old + increment; + + /* + * if we are giving memory back make sure we clear it out since + * we set MORECORE_CLEARS to 1 + */ + if (increment < 0) + memset((void *)new, 0, -increment); + + if ((new < mem_malloc_start) || (new > mem_malloc_end)) + return (void *)MORECORE_FAILURE; + + mem_malloc_brk = new; + + return (void *)old; +} + +void mem_malloc_init(ulong start, ulong size) +{ + mem_malloc_start = start; + mem_malloc_end = start + size; + mem_malloc_brk = start; + + memset((void *)mem_malloc_start, 0, size); + printf("malloc memory space: 0x%lx~0x%lx\n", start, start+size); +} + +/* field-extraction macros */ + +#define first(b) ((b)->fd) +#define last(b) ((b)->bk) + +/* + Indexing into bins +*/ + +#define bin_index(sz) \ +(((((unsigned long)(sz)) >> 9) == 0) ? (((unsigned long)(sz)) >> 3): \ + ((((unsigned long)(sz)) >> 9) <= 4) ? 56 + (((unsigned long)(sz)) >> 6): \ + ((((unsigned long)(sz)) >> 9) <= 20) ? 91 + (((unsigned long)(sz)) >> 9): \ + ((((unsigned long)(sz)) >> 9) <= 84) ? 110 + (((unsigned long)(sz)) >> 12): \ + ((((unsigned long)(sz)) >> 9) <= 340) ? 119 + (((unsigned long)(sz)) >> 15): \ + ((((unsigned long)(sz)) >> 9) <= 1364) ? 124 + (((unsigned long)(sz)) >> 18): \ + 126) +/* + bins for chunks < 512 are all spaced 8 bytes apart, and hold + identically sized chunks. This is exploited in malloc. +*/ + +#define MAX_SMALLBIN 63 +#define MAX_SMALLBIN_SIZE 512 +#define SMALLBIN_WIDTH 8 + +#define smallbin_index(sz) (((unsigned long)(sz)) >> 3) + +/* + Requests are `small' if both the corresponding and the next bin are small +*/ + +#define is_small_request(nb) (nb < MAX_SMALLBIN_SIZE - SMALLBIN_WIDTH) + + + +/* + To help compensate for the large number of bins, a one-level index + structure is used for bin-by-bin searching. `binblocks' is a + one-word bitvector recording whether groups of BINBLOCKWIDTH bins + have any (possibly) non-empty bins, so they can be skipped over + all at once during during traversals. The bits are NOT always + cleared as soon as all bins in a block are empty, but instead only + when all are noticed to be empty during traversal in malloc. +*/ + +#define BINBLOCKWIDTH 4 /* bins per block */ + +#define binblocks_r ((INTERNAL_SIZE_T)av_[1]) /* bitvector of nonempty blocks */ +#define binblocks_w (av_[1]) + +/* bin<->block macros */ + +#define idx2binblock(ix) ((unsigned)1 << (ix / BINBLOCKWIDTH)) +#define mark_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r | idx2binblock(ii))) +#define clear_binblock(ii) (binblocks_w = (mbinptr)(binblocks_r & ~(idx2binblock(ii)))) + + + + + +/* Other static bookkeeping data */ + +/* variables holding tunable values */ + +static unsigned long trim_threshold = DEFAULT_TRIM_THRESHOLD; +static unsigned long top_pad = DEFAULT_TOP_PAD; +static unsigned int n_mmaps_max = DEFAULT_MMAP_MAX; +static unsigned long mmap_threshold = DEFAULT_MMAP_THRESHOLD; + +/* The first value returned from sbrk */ +static char* sbrk_base = (char*)(-1); + +/* The maximum memory obtained from system via sbrk */ +static unsigned long max_sbrked_mem = 0; + +/* The maximum via either sbrk or mmap */ +static unsigned long max_total_mem = 0; + +/* internal working copy of mallinfo */ +static struct mallinfo current_mallinfo = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* The total memory obtained from system via sbrk */ +#define sbrked_mem (current_mallinfo.arena) + +/* Tracking mmaps */ + +#ifdef DEBUG +static unsigned int n_mmaps = 0; +#endif /* DEBUG */ +static unsigned long mmapped_mem = 0; +#if HAVE_MMAP +static unsigned int max_n_mmaps = 0; +static unsigned long max_mmapped_mem = 0; +#endif + + + +/* + Debugging support +*/ + +#ifdef DEBUG + + +/* + These routines make a number of assertions about the states + of data structures that should be true at all times. If any + are not true, it's very likely that a user program has somehow + trashed memory. (It's also possible that there is a coding error + in malloc. In which case, please report it!) +*/ + +#if __STD_C +static void do_check_chunk(mchunkptr p) +#else +static void do_check_chunk(p) mchunkptr p; +#endif +{ + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + + /* No checkable chunk is mmapped */ + assert(!chunk_is_mmapped(p)); + + /* Check for legal address ... */ + assert((char*)p >= sbrk_base); + if (p != top) + assert((char*)p + sz <= (char*)top); + else + assert((char*)p + sz <= sbrk_base + sbrked_mem); + +} + + +#if __STD_C +static void do_check_free_chunk(mchunkptr p) +#else +static void do_check_free_chunk(p) mchunkptr p; +#endif +{ + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + mchunkptr next = chunk_at_offset(p, sz); + + do_check_chunk(p); + + /* Check whether it claims to be free ... */ + assert(!inuse(p)); + + /* Unless a special marker, must have OK fields */ + if ((long)sz >= (long)MINSIZE) + { + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert(aligned_OK(chunk2mem(p))); + /* ... matching footer field */ + assert(next->prev_size == sz); + /* ... and is fully consolidated */ + assert(prev_inuse(p)); + assert (next == top || inuse(next)); + + /* ... and has minimally sane links */ + assert(p->fd->bk == p); + assert(p->bk->fd == p); + } + else /* markers are always of size SIZE_SZ */ + assert(sz == SIZE_SZ); +} + +#if __STD_C +static void do_check_inuse_chunk(mchunkptr p) +#else +static void do_check_inuse_chunk(p) mchunkptr p; +#endif +{ + mchunkptr next = next_chunk(p); + do_check_chunk(p); + + /* Check whether it claims to be in use ... */ + assert(inuse(p)); + + /* ... and is surrounded by OK chunks. + Since more things can be checked with free chunks than inuse ones, + if an inuse chunk borders them and debug is on, it's worth doing them. + */ + if (!prev_inuse(p)) + { + mchunkptr prv = prev_chunk(p); + assert(next_chunk(prv) == p); + do_check_free_chunk(prv); + } + if (next == top) + { + assert(prev_inuse(next)); + assert(chunksize(next) >= MINSIZE); + } + else if (!inuse(next)) + do_check_free_chunk(next); + +} + +#if __STD_C +static void do_check_malloced_chunk(mchunkptr p, INTERNAL_SIZE_T s) +#else +static void do_check_malloced_chunk(p, s) mchunkptr p; INTERNAL_SIZE_T s; +#endif +{ + INTERNAL_SIZE_T sz = p->size & ~PREV_INUSE; + long room = sz - s; + + do_check_inuse_chunk(p); + + /* Legal size ... */ + assert((long)sz >= (long)MINSIZE); + assert((sz & MALLOC_ALIGN_MASK) == 0); + assert(room >= 0); + assert(room < (long)MINSIZE); + + /* ... and alignment */ + assert(aligned_OK(chunk2mem(p))); + + + /* ... and was allocated at front of an available chunk */ + assert(prev_inuse(p)); + +} + + +#define check_free_chunk(P) do_check_free_chunk(P) +#define check_inuse_chunk(P) do_check_inuse_chunk(P) +#define check_chunk(P) do_check_chunk(P) +#define check_malloced_chunk(P,N) do_check_malloced_chunk(P,N) +#else +#define check_free_chunk(P) +#define check_inuse_chunk(P) +#define check_chunk(P) +#define check_malloced_chunk(P,N) +#endif + + + +/* + Macro-based internal utilities +*/ + + +/* + Linking chunks in bin lists. + Call these only with variables, not arbitrary expressions, as arguments. +*/ + +/* + Place chunk p of size s in its bin, in size order, + putting it ahead of others of same size. +*/ + + +#define frontlink(P, S, IDX, BK, FD) \ +{ \ + if (S < MAX_SMALLBIN_SIZE) \ + { \ + IDX = smallbin_index(S); \ + mark_binblock(IDX); \ + BK = bin_at(IDX); \ + FD = BK->fd; \ + P->bk = BK; \ + P->fd = FD; \ + FD->bk = BK->fd = P; \ + } \ + else \ + { \ + IDX = bin_index(S); \ + BK = bin_at(IDX); \ + FD = BK->fd; \ + if (FD == BK) mark_binblock(IDX); \ + else \ + { \ + while (FD != BK && S < chunksize(FD)) FD = FD->fd; \ + BK = FD->bk; \ + } \ + P->bk = BK; \ + P->fd = FD; \ + FD->bk = BK->fd = P; \ + } \ +} + + +/* take a chunk off a list */ + +#define unlink(P, BK, FD) \ +{ \ + BK = P->bk; \ + FD = P->fd; \ + FD->bk = BK; \ + BK->fd = FD; \ +} \ + +/* Place p as the last remainder */ + +#define link_last_remainder(P) \ +{ \ + last_remainder->fd = last_remainder->bk = P; \ + P->fd = P->bk = last_remainder; \ +} + +/* Clear the last_remainder bin */ + +#define clear_last_remainder \ + (last_remainder->fd = last_remainder->bk = last_remainder) + + + + + +/* Routines dealing with mmap(). */ + +#if HAVE_MMAP + +#if __STD_C +static mchunkptr mmap_chunk(size_t size) +#else +static mchunkptr mmap_chunk(size) size_t size; +#endif +{ + size_t page_mask = malloc_getpagesize - 1; + mchunkptr p; + +#ifndef MAP_ANONYMOUS + static int fd = -1; +#endif + + if(n_mmaps >= n_mmaps_max) return 0; /* too many regions */ + + /* For mmapped chunks, the overhead is one SIZE_SZ unit larger, because + * there is no following chunk whose prev_size field could be used. + */ + size = (size + SIZE_SZ + page_mask) & ~page_mask; + +#ifdef MAP_ANONYMOUS + p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +#else /* !MAP_ANONYMOUS */ + if (fd < 0) + { + fd = open("/dev/zero", O_RDWR); + if(fd < 0) return 0; + } + p = (mchunkptr)mmap(0, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); +#endif + + if(p == (mchunkptr)-1) return 0; + + n_mmaps++; + if (n_mmaps > max_n_mmaps) max_n_mmaps = n_mmaps; + + /* We demand that eight bytes into a page must be 8-byte aligned. */ + assert(aligned_OK(chunk2mem(p))); + + /* The offset to the start of the mmapped region is stored + * in the prev_size field of the chunk; normally it is zero, + * but that can be changed in memalign(). + */ + p->prev_size = 0; + set_head(p, size|IS_MMAPPED); + + mmapped_mem += size; + if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) + max_mmapped_mem = mmapped_mem; + if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) + max_total_mem = mmapped_mem + sbrked_mem; + return p; +} + +#if __STD_C +static void munmap_chunk(mchunkptr p) +#else +static void munmap_chunk(p) mchunkptr p; +#endif +{ + INTERNAL_SIZE_T size = chunksize(p); + int ret; + + assert (chunk_is_mmapped(p)); + assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); + assert((n_mmaps > 0)); + assert(((p->prev_size + size) & (malloc_getpagesize-1)) == 0); + + n_mmaps--; + mmapped_mem -= (size + p->prev_size); + + ret = munmap((char *)p - p->prev_size, size + p->prev_size); + + /* munmap returns non-zero on failure */ + assert(ret == 0); +} + +#if HAVE_MREMAP + +#if __STD_C +static mchunkptr mremap_chunk(mchunkptr p, size_t new_size) +#else +static mchunkptr mremap_chunk(p, new_size) mchunkptr p; size_t new_size; +#endif +{ + size_t page_mask = malloc_getpagesize - 1; + INTERNAL_SIZE_T offset = p->prev_size; + INTERNAL_SIZE_T size = chunksize(p); + char *cp; + + assert (chunk_is_mmapped(p)); + assert(! ((char*)p >= sbrk_base && (char*)p < sbrk_base + sbrked_mem)); + assert((n_mmaps > 0)); + assert(((size + offset) & (malloc_getpagesize-1)) == 0); + + /* Note the extra SIZE_SZ overhead as in mmap_chunk(). */ + new_size = (new_size + offset + SIZE_SZ + page_mask) & ~page_mask; + + cp = (char *)mremap((char *)p - offset, size + offset, new_size, 1); + + if (cp == (char *)-1) return 0; + + p = (mchunkptr)(cp + offset); + + assert(aligned_OK(chunk2mem(p))); + + assert((p->prev_size == offset)); + set_head(p, (new_size - offset)|IS_MMAPPED); + + mmapped_mem -= size + offset; + mmapped_mem += new_size; + if ((unsigned long)mmapped_mem > (unsigned long)max_mmapped_mem) + max_mmapped_mem = mmapped_mem; + if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) + max_total_mem = mmapped_mem + sbrked_mem; + return p; +} + +#endif /* HAVE_MREMAP */ + +#endif /* HAVE_MMAP */ + + + + +/* + Extend the top-most chunk by obtaining memory from system. + Main interface to sbrk (but see also malloc_trim). +*/ + +#if __STD_C +static void malloc_extend_top(INTERNAL_SIZE_T nb) +#else +static void malloc_extend_top(nb) INTERNAL_SIZE_T nb; +#endif +{ + char* brk; /* return value from sbrk */ + INTERNAL_SIZE_T front_misalign; /* unusable bytes at front of sbrked space */ + INTERNAL_SIZE_T correction; /* bytes for 2nd sbrk call */ + char* new_brk; /* return of 2nd sbrk call */ + INTERNAL_SIZE_T top_size; /* new size of top chunk */ + + mchunkptr old_top = top; /* Record state of old top */ + INTERNAL_SIZE_T old_top_size = chunksize(old_top); + char* old_end = (char*)(chunk_at_offset(old_top, old_top_size)); + + /* Pad request with top_pad plus minimal overhead */ + + INTERNAL_SIZE_T sbrk_size = nb + top_pad + MINSIZE; + unsigned long pagesz = malloc_getpagesize; + + /* If not the first time through, round to preserve page boundary */ + /* Otherwise, we need to correct to a page size below anyway. */ + /* (We also correct below if an intervening foreign sbrk call.) */ + + if (sbrk_base != (char*)(-1)) + sbrk_size = (sbrk_size + (pagesz - 1)) & ~(pagesz - 1); + + brk = (char*)(MORECORE (sbrk_size)); + + /* Fail if sbrk failed or if a foreign sbrk call killed our space */ + if (brk == (char*)(MORECORE_FAILURE) || + (brk < old_end && old_top != initial_top)) + return; + + sbrked_mem += sbrk_size; + + if (brk == old_end) /* can just add bytes to current top */ + { + top_size = sbrk_size + old_top_size; + set_head(top, top_size | PREV_INUSE); + } + else + { + if (sbrk_base == (char*)(-1)) /* First time through. Record base */ + sbrk_base = brk; + else /* Someone else called sbrk(). Count those bytes as sbrked_mem. */ + sbrked_mem += brk - (char*)old_end; + + /* Guarantee alignment of first new chunk made from this space */ + front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK; + if (front_misalign > 0) + { + correction = (MALLOC_ALIGNMENT) - front_misalign; + brk += correction; + } + else + correction = 0; + + /* Guarantee the next brk will be at a page boundary */ + + correction += ((((unsigned long)(brk + sbrk_size))+(pagesz-1)) & + ~(pagesz - 1)) - ((unsigned long)(brk + sbrk_size)); + + /* Allocate correction */ + new_brk = (char*)(MORECORE (correction)); + if (new_brk == (char*)(MORECORE_FAILURE)) return; + + sbrked_mem += correction; + + top = (mchunkptr)brk; + top_size = new_brk - brk + correction; + set_head(top, top_size | PREV_INUSE); + + if (old_top != initial_top) + { + + /* There must have been an intervening foreign sbrk call. */ + /* A double fencepost is necessary to prevent consolidation */ + + /* If not enough space to do this, then user did something very wrong */ + if (old_top_size < MINSIZE) + { + set_head(top, PREV_INUSE); /* will force null return from malloc */ + return; + } + + /* Also keep size a multiple of MALLOC_ALIGNMENT */ + old_top_size = (old_top_size - 3*SIZE_SZ) & ~MALLOC_ALIGN_MASK; + set_head_size(old_top, old_top_size); + chunk_at_offset(old_top, old_top_size )->size = + SIZE_SZ|PREV_INUSE; + chunk_at_offset(old_top, old_top_size + SIZE_SZ)->size = + SIZE_SZ|PREV_INUSE; + /* If possible, release the rest. */ + if (old_top_size >= MINSIZE) + fREe(chunk2mem(old_top)); + } + } + + if ((unsigned long)sbrked_mem > (unsigned long)max_sbrked_mem) + max_sbrked_mem = sbrked_mem; + if ((unsigned long)(mmapped_mem + sbrked_mem) > (unsigned long)max_total_mem) + max_total_mem = mmapped_mem + sbrked_mem; + + /* We always land on a page boundary */ + assert(((unsigned long)((char*)top + top_size) & (pagesz - 1)) == 0); +} + + + + +/* Main public routines */ + + +/* + Malloc Algorthim: + + The requested size is first converted into a usable form, `nb'. + This currently means to add 4 bytes overhead plus possibly more to + obtain 8-byte alignment and/or to obtain a size of at least + MINSIZE (currently 16 bytes), the smallest allocatable size. + (All fits are considered `exact' if they are within MINSIZE bytes.) + + From there, the first successful of the following steps is taken: + + 1. The bin corresponding to the request size is scanned, and if + a chunk of exactly the right size is found, it is taken. + + 2. The most recently remaindered chunk is used if it is big + enough. This is a form of (roving) first fit, used only in + the absence of exact fits. Runs of consecutive requests use + the remainder of the chunk used for the previous such request + whenever possible. This limited use of a first-fit style + allocation strategy tends to give contiguous chunks + coextensive lifetimes, which improves locality and can reduce + fragmentation in the long run. + + 3. Other bins are scanned in increasing size order, using a + chunk big enough to fulfill the request, and splitting off + any remainder. This search is strictly by best-fit; i.e., + the smallest (with ties going to approximately the least + recently used) chunk that fits is selected. + + 4. If large enough, the chunk bordering the end of memory + (`top') is split off. (This use of `top' is in accord with + the best-fit search rule. In effect, `top' is treated as + larger (and thus less well fitting) than any other available + chunk since it can be extended to be as large as necessary + (up to system limitations). + + 5. If the request size meets the mmap threshold and the + system supports mmap, and there are few enough currently + allocated mmapped regions, and a call to mmap succeeds, + the request is allocated via direct memory mapping. + + 6. Otherwise, the top of memory is extended by + obtaining more space from the system (normally using sbrk, + but definable to anything else via the MORECORE macro). + Memory is gathered from the system (in system page-sized + units) in a way that allows chunks obtained across different + sbrk calls to be consolidated, but does not require + contiguous memory. Thus, it should be safe to intersperse + mallocs with other sbrk calls. + + + All allocations are made from the the `lowest' part of any found + chunk. (The implementation invariant is that prev_inuse is + always true of any allocated chunk; i.e., that each allocated + chunk borders either a previously allocated and still in-use chunk, + or the base of its memory arena.) + +*/ + +#if __STD_C +Void_t* mALLOc(size_t bytes) +#else +Void_t* mALLOc(bytes) size_t bytes; +#endif +{ + mchunkptr victim; /* inspected/selected chunk */ + INTERNAL_SIZE_T victim_size; /* its size */ + int idx; /* index for bin traversal */ + mbinptr bin; /* associated bin */ + mchunkptr remainder; /* remainder from a split */ + long remainder_size; /* its size */ + int remainder_index; /* its bin index */ + unsigned long block; /* block traverser bit */ + int startidx; /* first bin of a traversed block */ + mchunkptr fwd; /* misc temp for linking */ + mchunkptr bck; /* misc temp for linking */ + mbinptr q; /* misc temp */ + + INTERNAL_SIZE_T nb; + + /* check if mem_malloc_init() was run */ + if ((mem_malloc_start == 0) && (mem_malloc_end == 0)) { + /* not initialized yet */ + return NULL; + } + + if ((long)bytes < 0) return NULL; + + nb = request2size(bytes); /* padded request size; */ + + /* Check for exact match in a bin */ + + if (is_small_request(nb)) /* Faster version for small requests */ + { + idx = smallbin_index(nb); + + /* No traversal or size check necessary for small bins. */ + + q = bin_at(idx); + victim = last(q); + + /* Also scan the next one, since it would have a remainder < MINSIZE */ + if (victim == q) + { + q = next_bin(q); + victim = last(q); + } + if (victim != q) + { + victim_size = chunksize(victim); + unlink(victim, bck, fwd); + set_inuse_bit_at_offset(victim, victim_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + idx += 2; /* Set for bin scan below. We've already scanned 2 bins. */ + + } + else + { + idx = bin_index(nb); + bin = bin_at(idx); + + for (victim = last(bin); victim != bin; victim = victim->bk) + { + victim_size = chunksize(victim); + remainder_size = victim_size - nb; + + if (remainder_size >= (long)MINSIZE) /* too big */ + { + --idx; /* adjust to rescan below after checking last remainder */ + break; + } + + else if (remainder_size >= 0) /* exact fit */ + { + unlink(victim, bck, fwd); + set_inuse_bit_at_offset(victim, victim_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + } + + ++idx; + + } + + /* Try to use the last split-off remainder */ + + if ( (victim = last_remainder->fd) != last_remainder) + { + victim_size = chunksize(victim); + remainder_size = victim_size - nb; + + if (remainder_size >= (long)MINSIZE) /* re-split */ + { + remainder = chunk_at_offset(victim, nb); + set_head(victim, nb | PREV_INUSE); + link_last_remainder(remainder); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + clear_last_remainder; + + if (remainder_size >= 0) /* exhaust */ + { + set_inuse_bit_at_offset(victim, victim_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + /* Else place in bin */ + + frontlink(victim, victim_size, remainder_index, bck, fwd); + } + + /* + If there are any possibly nonempty big-enough blocks, + search for best fitting chunk by scanning bins in blockwidth units. + */ + + if ( (block = idx2binblock(idx)) <= binblocks_r) + { + + /* Get to the first marked block */ + + if ( (block & binblocks_r) == 0) + { + /* force to an even block boundary */ + idx = (idx & ~(BINBLOCKWIDTH - 1)) + BINBLOCKWIDTH; + block <<= 1; + while ((block & binblocks_r) == 0) + { + idx += BINBLOCKWIDTH; + block <<= 1; + } + } + + /* For each possibly nonempty block ... */ + for (;;) + { + startidx = idx; /* (track incomplete blocks) */ + q = bin = bin_at(idx); + + /* For each bin in this block ... */ + do + { + /* Find and use first big enough chunk ... */ + + for (victim = last(bin); victim != bin; victim = victim->bk) + { + victim_size = chunksize(victim); + remainder_size = victim_size - nb; + + if (remainder_size >= (long)MINSIZE) /* split */ + { + remainder = chunk_at_offset(victim, nb); + set_head(victim, nb | PREV_INUSE); + unlink(victim, bck, fwd); + link_last_remainder(remainder); + set_head(remainder, remainder_size | PREV_INUSE); + set_foot(remainder, remainder_size); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + else if (remainder_size >= 0) /* take */ + { + set_inuse_bit_at_offset(victim, victim_size); + unlink(victim, bck, fwd); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + } + + } + + bin = next_bin(bin); + + } while ((++idx & (BINBLOCKWIDTH - 1)) != 0); + + /* Clear out the block bit. */ + + do /* Possibly backtrack to try to clear a partial block */ + { + if ((startidx & (BINBLOCKWIDTH - 1)) == 0) + { + av_[1] = (mbinptr)(binblocks_r & ~block); + break; + } + --startidx; + q = prev_bin(q); + } while (first(q) == q); + + /* Get to the next possibly nonempty block */ + + if ( (block <<= 1) <= binblocks_r && (block != 0) ) + { + while ((block & binblocks_r) == 0) + { + idx += BINBLOCKWIDTH; + block <<= 1; + } + } + else + break; + } + } + + + /* Try to use top chunk */ + + /* Require that there be a remainder, ensuring top always exists */ + if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) + { + +#if HAVE_MMAP + /* If big and would otherwise need to extend, try to use mmap instead */ + if ((unsigned long)nb >= (unsigned long)mmap_threshold && + (victim = mmap_chunk(nb)) != 0) + return chunk2mem(victim); +#endif + + /* Try to extend */ + malloc_extend_top(nb); + if ( (remainder_size = chunksize(top) - nb) < (long)MINSIZE) + return NULL; /* propagate failure */ + } + + victim = top; + set_head(victim, nb | PREV_INUSE); + top = chunk_at_offset(victim, nb); + set_head(top, remainder_size | PREV_INUSE); + check_malloced_chunk(victim, nb); + return chunk2mem(victim); + +} + + + + +/* + + free() algorithm : + + cases: + + 1. free(0) has no effect. + + 2. If the chunk was allocated via mmap, it is release via munmap(). + + 3. If a returned chunk borders the current high end of memory, + it is consolidated into the top, and if the total unused + topmost memory exceeds the trim threshold, malloc_trim is + called. + + 4. Other chunks are consolidated as they arrive, and + placed in corresponding bins. (This includes the case of + consolidating with the current `last_remainder'). + +*/ + + +#if __STD_C +void fREe(Void_t* mem) +#else +void fREe(mem) Void_t* mem; +#endif +{ + mchunkptr p; /* chunk corresponding to mem */ + INTERNAL_SIZE_T hd; /* its head field */ + INTERNAL_SIZE_T sz; /* its size */ + int idx; /* its bin index */ + mchunkptr next; /* next contiguous chunk */ + INTERNAL_SIZE_T nextsz; /* its size */ + INTERNAL_SIZE_T prevsz; /* size of previous contiguous chunk */ + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + int islr; /* track whether merging with last_remainder */ + + if (mem == NULL) /* free(0) has no effect */ + return; + + p = mem2chunk(mem); + hd = p->size; + +#if HAVE_MMAP + if (hd & IS_MMAPPED) /* release mmapped memory. */ + { + munmap_chunk(p); + return; + } +#endif + + check_inuse_chunk(p); + + sz = hd & ~PREV_INUSE; + next = chunk_at_offset(p, sz); + nextsz = chunksize(next); + + if (next == top) /* merge with top */ + { + sz += nextsz; + + if (!(hd & PREV_INUSE)) /* consolidate backward */ + { + prevsz = p->prev_size; + p = chunk_at_offset(p, -((long) prevsz)); + sz += prevsz; + unlink(p, bck, fwd); + } + + set_head(p, sz | PREV_INUSE); + top = p; + if ((unsigned long)(sz) >= (unsigned long)trim_threshold) + malloc_trim(top_pad); + return; + } + + set_head(next, nextsz); /* clear inuse bit */ + + islr = 0; + + if (!(hd & PREV_INUSE)) /* consolidate backward */ + { + prevsz = p->prev_size; + p = chunk_at_offset(p, -((long) prevsz)); + sz += prevsz; + + if (p->fd == last_remainder) /* keep as last_remainder */ + islr = 1; + else + unlink(p, bck, fwd); + } + + if (!(inuse_bit_at_offset(next, nextsz))) /* consolidate forward */ + { + sz += nextsz; + + if (!islr && next->fd == last_remainder) /* re-insert last_remainder */ + { + islr = 1; + link_last_remainder(p); + } + else + unlink(next, bck, fwd); + } + + + set_head(p, sz | PREV_INUSE); + set_foot(p, sz); + if (!islr) + frontlink(p, sz, idx, bck, fwd); +} + + + + + +/* + + Realloc algorithm: + + Chunks that were obtained via mmap cannot be extended or shrunk + unless HAVE_MREMAP is defined, in which case mremap is used. + Otherwise, if their reallocation is for additional space, they are + copied. If for less, they are just left alone. + + Otherwise, if the reallocation is for additional space, and the + chunk can be extended, it is, else a malloc-copy-free sequence is + taken. There are several different ways that a chunk could be + extended. All are tried: + + * Extending forward into following adjacent free chunk. + * Shifting backwards, joining preceding adjacent space + * Both shifting backwards and extending forward. + * Extending into newly sbrked space + + Unless the #define REALLOC_ZERO_BYTES_FREES is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + + If the reallocation is for less space, and the new request is for + a `small' (<512 bytes) size, then the newly unused space is lopped + off and freed. + + The old unix realloc convention of allowing the last-free'd chunk + to be used as an argument to realloc is no longer supported. + I don't know of any programs still relying on this feature, + and allowing it would also allow too many other incorrect + usages of realloc to be sensible. + + +*/ + + +#if __STD_C +Void_t* rEALLOc(Void_t* oldmem, size_t bytes) +#else +Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes; +#endif +{ + INTERNAL_SIZE_T nb; /* padded request size */ + + mchunkptr oldp; /* chunk corresponding to oldmem */ + INTERNAL_SIZE_T oldsize; /* its size */ + + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + Void_t* newmem; /* corresponding user mem */ + + mchunkptr next; /* next contiguous chunk after oldp */ + INTERNAL_SIZE_T nextsize; /* its size */ + + mchunkptr prev; /* previous contiguous chunk before oldp */ + INTERNAL_SIZE_T prevsize; /* its size */ + + mchunkptr remainder; /* holds split off extra space from newp */ + INTERNAL_SIZE_T remainder_size; /* its size */ + + mchunkptr bck; /* misc temp for linking */ + mchunkptr fwd; /* misc temp for linking */ + +#ifdef REALLOC_ZERO_BYTES_FREES + if (bytes == 0) { fREe(oldmem); return 0; } +#endif + + if ((long)bytes < 0) return NULL; + + /* realloc of null is supposed to be same as malloc */ + if (oldmem == NULL) return mALLOc(bytes); + + newp = oldp = mem2chunk(oldmem); + newsize = oldsize = chunksize(oldp); + + + nb = request2size(bytes); + +#if HAVE_MMAP + if (chunk_is_mmapped(oldp)) + { +#if HAVE_MREMAP + newp = mremap_chunk(oldp, nb); + if(newp) return chunk2mem(newp); +#endif + /* Note the extra SIZE_SZ overhead. */ + if(oldsize - SIZE_SZ >= nb) return oldmem; /* do nothing */ + /* Must alloc, copy, free. */ + newmem = mALLOc(bytes); + if (newmem == 0) return 0; /* propagate failure */ + MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ); + munmap_chunk(oldp); + return newmem; + } +#endif + + check_inuse_chunk(oldp); + + if ((long)(oldsize) < (long)(nb)) + { + + /* Try expanding forward */ + + next = chunk_at_offset(oldp, oldsize); + if (next == top || !inuse(next)) + { + nextsize = chunksize(next); + + /* Forward into top only if a remainder */ + if (next == top) + { + if ((long)(nextsize + newsize) >= (long)(nb + MINSIZE)) + { + newsize += nextsize; + top = chunk_at_offset(oldp, nb); + set_head(top, (newsize - nb) | PREV_INUSE); + set_head_size(oldp, nb); + return chunk2mem(oldp); + } + } + + /* Forward into next chunk */ + else if (((long)(nextsize + newsize) >= (long)(nb))) + { + unlink(next, bck, fwd); + newsize += nextsize; + goto split; + } + } + else + { + next = NULL; + nextsize = 0; + } + + /* Try shifting backwards. */ + + if (!prev_inuse(oldp)) + { + prev = prev_chunk(oldp); + prevsize = chunksize(prev); + + /* try forward + backward first to save a later consolidation */ + + if (next != NULL) + { + /* into top */ + if (next == top) + { + if ((long)(nextsize + prevsize + newsize) >= (long)(nb + MINSIZE)) + { + unlink(prev, bck, fwd); + newp = prev; + newsize += prevsize + nextsize; + newmem = chunk2mem(newp); + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + top = chunk_at_offset(newp, nb); + set_head(top, (newsize - nb) | PREV_INUSE); + set_head_size(newp, nb); + return newmem; + } + } + + /* into next chunk */ + else if (((long)(nextsize + prevsize + newsize) >= (long)(nb))) + { + unlink(next, bck, fwd); + unlink(prev, bck, fwd); + newp = prev; + newsize += nextsize + prevsize; + newmem = chunk2mem(newp); + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + goto split; + } + } + + /* backward only */ + if (prev != NULL && (long)(prevsize + newsize) >= (long)nb) + { + unlink(prev, bck, fwd); + newp = prev; + newsize += prevsize; + newmem = chunk2mem(newp); + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + goto split; + } + } + + /* Must allocate */ + + newmem = mALLOc (bytes); + + if (newmem == NULL) /* propagate failure */ + return NULL; + + /* Avoid copy if newp is next chunk after oldp. */ + /* (This can only happen when new chunk is sbrk'ed.) */ + + if ( (newp = mem2chunk(newmem)) == next_chunk(oldp)) + { + newsize += chunksize(newp); + newp = oldp; + goto split; + } + + /* Otherwise copy, free, and exit */ + MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ); + fREe(oldmem); + return newmem; + } + + + split: /* split off extra room in old or expanded chunk */ + + if (newsize - nb >= MINSIZE) /* split off remainder */ + { + remainder = chunk_at_offset(newp, nb); + remainder_size = newsize - nb; + set_head_size(newp, nb); + set_head(remainder, remainder_size | PREV_INUSE); + set_inuse_bit_at_offset(remainder, remainder_size); + fREe(chunk2mem(remainder)); /* let free() deal with it */ + } + else + { + set_head_size(newp, newsize); + set_inuse_bit_at_offset(newp, newsize); + } + + check_inuse_chunk(newp); + return chunk2mem(newp); +} + + + + +/* + + memalign algorithm: + + memalign requests more than enough space from malloc, finds a spot + within that chunk that meets the alignment request, and then + possibly frees the leading and trailing space. + + The alignment argument must be a power of two. This property is not + checked by memalign, so misuse may result in random runtime errors. + + 8-byte alignment is guaranteed by normal malloc calls, so don't + bother calling memalign with an argument of 8 or less. + + Overreliance on memalign is a sure way to fragment space. + +*/ + + +#if __STD_C +Void_t* mEMALIGn(size_t alignment, size_t bytes) +#else +Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes; +#endif +{ + INTERNAL_SIZE_T nb; /* padded request size */ + char* m; /* memory returned by malloc call */ + mchunkptr p; /* corresponding chunk */ + char* brk; /* alignment point within p */ + mchunkptr newp; /* chunk to return */ + INTERNAL_SIZE_T newsize; /* its size */ + INTERNAL_SIZE_T leadsize; /* leading space befor alignment point */ + mchunkptr remainder; /* spare room at end to split off */ + long remainder_size; /* its size */ + + if ((long)bytes < 0) return NULL; + + /* If need less alignment than we give anyway, just relay to malloc */ + + if (alignment <= MALLOC_ALIGNMENT) return mALLOc(bytes); + + /* Otherwise, ensure that it is at least a minimum chunk size */ + + if (alignment < MINSIZE) alignment = MINSIZE; + + /* Call malloc with worst case padding to hit alignment. */ + + nb = request2size(bytes); + m = (char*)(mALLOc(nb + alignment + MINSIZE)); + + if (m == NULL) return NULL; /* propagate failure */ + + p = mem2chunk(m); + + if ((((unsigned long)(m)) % alignment) == 0) /* aligned */ + { +#if HAVE_MMAP + if(chunk_is_mmapped(p)) + return chunk2mem(p); /* nothing more to do */ +#endif + } + else /* misaligned */ + { + /* + Find an aligned spot inside chunk. + Since we need to give back leading space in a chunk of at + least MINSIZE, if the first calculation places us at + a spot with less than MINSIZE leader, we can move to the + next aligned spot -- we've allocated enough total room so that + this is always possible. + */ + + brk = (char*)mem2chunk(((unsigned long)(m + alignment - 1)) & -((signed) alignment)); + if ((long)(brk - (char*)(p)) < MINSIZE) brk = brk + alignment; + + newp = (mchunkptr)brk; + leadsize = brk - (char*)(p); + newsize = chunksize(p) - leadsize; + +#if HAVE_MMAP + if(chunk_is_mmapped(p)) + { + newp->prev_size = p->prev_size + leadsize; + set_head(newp, newsize|IS_MMAPPED); + return chunk2mem(newp); + } +#endif + + /* give back leader, use the rest */ + + set_head(newp, newsize | PREV_INUSE); + set_inuse_bit_at_offset(newp, newsize); + set_head_size(p, leadsize); + fREe(chunk2mem(p)); + p = newp; + + assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0); + } + + /* Also give back spare room at the end */ + + remainder_size = chunksize(p) - nb; + + if (remainder_size >= (long)MINSIZE) + { + remainder = chunk_at_offset(p, nb); + set_head(remainder, remainder_size | PREV_INUSE); + set_head_size(p, nb); + fREe(chunk2mem(remainder)); + } + + check_inuse_chunk(p); + return chunk2mem(p); + +} + + + + +/* + valloc just invokes memalign with alignment argument equal + to the page size of the system (or as near to this as can + be figured out from all the includes/defines above.) +*/ + +#if __STD_C +Void_t* vALLOc(size_t bytes) +#else +Void_t* vALLOc(bytes) size_t bytes; +#endif +{ + return mEMALIGn (malloc_getpagesize, bytes); +} + +/* + pvalloc just invokes valloc for the nearest pagesize + that will accommodate request +*/ + + +#if __STD_C +Void_t* pvALLOc(size_t bytes) +#else +Void_t* pvALLOc(bytes) size_t bytes; +#endif +{ + size_t pagesize = malloc_getpagesize; + return mEMALIGn (pagesize, (bytes + pagesize - 1) & ~(pagesize - 1)); +} + +/* + + calloc calls malloc, then zeroes out the allocated chunk. + +*/ + +#if __STD_C +Void_t* cALLOc(size_t n, size_t elem_size) +#else +Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size; +#endif +{ + mchunkptr p; + INTERNAL_SIZE_T csz; + + INTERNAL_SIZE_T sz = n * elem_size; + + + /* check if expand_top called, in which case don't need to clear */ +#if MORECORE_CLEARS + mchunkptr oldtop = top; + INTERNAL_SIZE_T oldtopsize = chunksize(top); +#endif + Void_t* mem = mALLOc (sz); + + if ((long)n < 0) return NULL; + + if (mem == NULL) + return NULL; + else + { + p = mem2chunk(mem); + + /* Two optional cases in which clearing not necessary */ + + +#if HAVE_MMAP + if (chunk_is_mmapped(p)) return mem; +#endif + + csz = chunksize(p); + +#if MORECORE_CLEARS + if (p == oldtop && csz > oldtopsize) + { + /* clear only the bytes from non-freshly-sbrked memory */ + csz = oldtopsize; + } +#endif + + MALLOC_ZERO(mem, csz - SIZE_SZ); + return mem; + } +} + +/* + + cfree just calls free. It is needed/defined on some systems + that pair it with calloc, presumably for odd historical reasons. + +*/ + +#if !defined(INTERNAL_LINUX_C_LIB) || !defined(__ELF__) +#if __STD_C +void cfree(Void_t *mem) +#else +void cfree(mem) Void_t *mem; +#endif +{ + fREe(mem); +} +#endif + + + +/* + + Malloc_trim gives memory back to the system (via negative + arguments to sbrk) if there is unused memory at the `high' end of + the malloc pool. You can call this after freeing large blocks of + memory to potentially reduce the system-level memory requirements + of a program. However, it cannot guarantee to reduce memory. Under + some allocation patterns, some large free blocks of memory will be + locked between two used chunks, so they cannot be given back to + the system. + + The `pad' argument to malloc_trim represents the amount of free + trailing space to leave untrimmed. If this argument is zero, + only the minimum amount of memory to maintain internal data + structures will be left (one page or less). Non-zero arguments + can be supplied to maintain enough trailing space to service + future expected allocations without having to re-obtain memory + from the system. + + Malloc_trim returns 1 if it actually released any memory, else 0. + +*/ + +#if __STD_C +int malloc_trim(size_t pad) +#else +int malloc_trim(pad) size_t pad; +#endif +{ + long top_size; /* Amount of top-most memory */ + long extra; /* Amount to release */ + char* current_brk; /* address returned by pre-check sbrk call */ + char* new_brk; /* address returned by negative sbrk call */ + + unsigned long pagesz = malloc_getpagesize; + + top_size = chunksize(top); + extra = ((top_size - pad - MINSIZE + (pagesz-1)) / pagesz - 1) * pagesz; + + if (extra < (long)pagesz) /* Not enough memory to release */ + return 0; + + else + { + /* Test to make sure no one else called sbrk */ + current_brk = (char*)(MORECORE (0)); + if (current_brk != (char*)(top) + top_size) + return 0; /* Apparently we don't own memory; must fail */ + + else + { + new_brk = (char*)(MORECORE (-extra)); + + if (new_brk == (char*)(MORECORE_FAILURE)) /* sbrk failed? */ + { + /* Try to figure out what we have */ + current_brk = (char*)(MORECORE (0)); + top_size = current_brk - (char*)top; + if (top_size >= (long)MINSIZE) /* if not, we are very very dead! */ + { + sbrked_mem = current_brk - sbrk_base; + set_head(top, top_size | PREV_INUSE); + } + check_chunk(top); + return 0; + } + + else + { + /* Success. Adjust top accordingly. */ + set_head(top, (top_size - extra) | PREV_INUSE); + sbrked_mem -= extra; + check_chunk(top); + return 1; + } + } + } +} + + + +/* + malloc_usable_size: + + This routine tells you how many bytes you can actually use in an + allocated chunk, which may be more than you requested (although + often not). You can use this many bytes without worrying about + overwriting other allocated objects. Not a particularly great + programming practice, but still sometimes useful. + +*/ + +#if __STD_C +size_t malloc_usable_size(Void_t* mem) +#else +size_t malloc_usable_size(mem) Void_t* mem; +#endif +{ + mchunkptr p; + if (mem == NULL) + return 0; + else + { + p = mem2chunk(mem); + if(!chunk_is_mmapped(p)) + { + if (!inuse(p)) return 0; + check_inuse_chunk(p); + return chunksize(p) - SIZE_SZ; + } + return chunksize(p) - 2*SIZE_SZ; + } +} + + + + +/* Utility to update current_mallinfo for malloc_stats and mallinfo() */ + +#ifdef DEBUG +static void malloc_update_mallinfo() +{ + int i; + mbinptr b; + mchunkptr p; +#ifdef DEBUG + mchunkptr q; +#endif + + INTERNAL_SIZE_T avail = chunksize(top); + int navail = ((long)(avail) >= (long)MINSIZE)? 1 : 0; + + for (i = 1; i < NAV; ++i) + { + b = bin_at(i); + for (p = last(b); p != b; p = p->bk) + { +#ifdef DEBUG + check_free_chunk(p); + for (q = next_chunk(p); + q < top && inuse(q) && (long)(chunksize(q)) >= (long)MINSIZE; + q = next_chunk(q)) + check_inuse_chunk(q); +#endif + avail += chunksize(p); + navail++; + } + } + + current_mallinfo.ordblks = navail; + current_mallinfo.uordblks = sbrked_mem - avail; + current_mallinfo.fordblks = avail; + current_mallinfo.hblks = n_mmaps; + current_mallinfo.hblkhd = mmapped_mem; + current_mallinfo.keepcost = chunksize(top); + +} +#endif /* DEBUG */ + + + +/* + + malloc_stats: + + Prints on the amount of space obtain from the system (both + via sbrk and mmap), the maximum amount (which may be more than + current if malloc_trim and/or munmap got called), the maximum + number of simultaneous mmap regions used, and the current number + of bytes allocated via malloc (or realloc, etc) but not yet + freed. (Note that this is the number of bytes allocated, not the + number requested. It will be larger than the number requested + because of alignment and bookkeeping overhead.) + +*/ + +#ifdef DEBUG +void malloc_stats() +{ + malloc_update_mallinfo(); + printf("max system bytes = %10u\n", + (unsigned int)(max_total_mem)); + printf("system bytes = %10u\n", + (unsigned int)(sbrked_mem + mmapped_mem)); + printf("in use bytes = %10u\n", + (unsigned int)(current_mallinfo.uordblks + mmapped_mem)); +#if HAVE_MMAP + printf("max mmap regions = %10u\n", + (unsigned int)max_n_mmaps); +#endif +} +#endif /* DEBUG */ + +/* + mallinfo returns a copy of updated current mallinfo. +*/ + +#ifdef DEBUG +struct mallinfo mALLINFo() +{ + malloc_update_mallinfo(); + return current_mallinfo; +} +#endif /* DEBUG */ + + + + +/* + mallopt: + + mallopt is the general SVID/XPG interface to tunable parameters. + The format is to provide a (parameter-number, parameter-value) pair. + mallopt then sets the corresponding parameter to the argument + value if it can (i.e., so long as the value is meaningful), + and returns 1 if successful else 0. + + See descriptions of tunable parameters above. + +*/ + +#if __STD_C +int mALLOPt(int param_number, int value) +#else +int mALLOPt(param_number, value) int param_number; int value; +#endif +{ + switch(param_number) + { + case M_TRIM_THRESHOLD: + trim_threshold = value; return 1; + case M_TOP_PAD: + top_pad = value; return 1; + case M_MMAP_THRESHOLD: + mmap_threshold = value; return 1; + case M_MMAP_MAX: +#if HAVE_MMAP + n_mmaps_max = value; return 1; +#else + if (value != 0) return 0; else n_mmaps_max = value; return 1; +#endif + + default: + return 0; + } +} + +/* + +History: + + V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) + * return null for negative arguments + * Added Several WIN32 cleanups from Martin C. Fong <mcfong@yahoo.com> + * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' + (e.g. WIN32 platforms) + * Cleanup up header file inclusion for WIN32 platforms + * Cleanup code to avoid Microsoft Visual C++ compiler complaints + * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing + memory allocation routines + * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) + * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to + usage of 'assert' in non-WIN32 code + * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to + avoid infinite loop + * Always call 'fREe()' rather than 'free()' + + V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) + * Fixed ordering problem with boundary-stamping + + V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) + * Added pvalloc, as recommended by H.J. Liu + * Added 64bit pointer support mainly from Wolfram Gloger + * Added anonymously donated WIN32 sbrk emulation + * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen + * malloc_extend_top: fix mask error that caused wastage after + foreign sbrks + * Add linux mremap support code from HJ Liu + + V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) + * Integrated most documentation with the code. + * Add support for mmap, with help from + Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Use last_remainder in more cases. + * Pack bins using idea from colin@nyx10.cs.du.edu + * Use ordered bins instead of best-fit threshhold + * Eliminate block-local decls to simplify tracing and debugging. + * Support another case of realloc via move into top + * Fix error occuring when initial sbrk_base not word-aligned. + * Rely on page size for units instead of SBRK_UNIT to + avoid surprises about sbrk alignment conventions. + * Add mallinfo, mallopt. Thanks to Raymond Nijssen + (raymond@es.ele.tue.nl) for the suggestion. + * Add `pad' argument to malloc_trim and top_pad mallopt parameter. + * More precautions for cases where other routines call sbrk, + courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). + * Added macros etc., allowing use in linux libc from + H.J. Lu (hjl@gnu.ai.mit.edu) + * Inverted this history list + + V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) + * Re-tuned and fixed to behave more nicely with V2.6.0 changes. + * Removed all preallocation code since under current scheme + the work required to undo bad preallocations exceeds + the work saved in good cases for most test programs. + * No longer use return list or unconsolidated bins since + no scheme using them consistently outperforms those that don't + given above changes. + * Use best fit for very large chunks to prevent some worst-cases. + * Added some support for debugging + + V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) + * Removed footers when chunks are in use. Thanks to + Paul Wilson (wilson@cs.texas.edu) for the suggestion. + + V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) + * Added malloc_trim, with help from Wolfram Gloger + (wmglo@Dent.MED.Uni-Muenchen.DE). + + V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) + + V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) + * realloc: try to expand in both directions + * malloc: swap order of clean-bin strategy; + * realloc: only conditionally expand backwards + * Try not to scavenge used bins + * Use bin counts as a guide to preallocation + * Occasionally bin return list chunks in first scan + * Add a few optimizations from colin@nyx10.cs.du.edu + + V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) + * faster bin computation & slightly different binning + * merged all consolidations to one part of malloc proper + (eliminating old malloc_find_space & malloc_clean_bin) + * Scan 2 returns chunks (not just 1) + * Propagate failure in realloc if malloc returns 0 + * Add stuff to allow compilation on non-ANSI compilers + from kpv@research.att.com + + V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) + * removed potential for odd address access in prev_chunk + * removed dependency on getpagesize.h + * misc cosmetics and a bit more internal documentation + * anticosmetics: mangled names in macros to evade debugger strangeness + * tested on sparc, hp-700, dec-mips, rs6000 + with gcc & native cc (hp, dec only) allowing + Detlefs & Zorn comparison study (in SIGPLAN Notices.) + + Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) + * Based loosely on libg++-1.2X malloc. (It retains some of the overall + structure of old version, but most details differ.) + +*/ diff --git a/linux-bsp/asm-study/yaffs2/common/makefile b/linux-bsp/asm-study/yaffs2/common/makefile new file mode 100644 index 0000000..78e9641 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/makefile @@ -0,0 +1,97 @@ +#********************************************************************************* +# Copyright: (C) 2012 CoherentPlus Sdn. Bhd. +# All rights reserved. +# +# Filename: Makefile +# Description: This is the common subdir Makefile which to compile all the C +# source code to object files and then generate the shared or +# static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so, +# which depends on the variable $LINK_MODE. +# +# Version: 1.0.0(10/08/2011~) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "10/08/2011 01:29:33 AM" +# +#********************************************************************************/ + +PWD=$(shell pwd) +LOCAL_COMPILE=YES +LINK_MODE=STATIC + +#If wanna compile in the subdir, not called by top makefile, uncomment it +ifneq (${TOP_COMPILE}, YES) +LOCAL_COMPILE=YES +endif + +LIBNAME=$(shell basename ${PWD}) +STALIB=lib${LIBNAME}.a +DYNLIB=lib${LIBNAME}.so + +VPATH= . +SRCS = $(wildcard ${VPATH}/*.c) +OBJS = $(patsubst %.c,%.o,$(SRCS)) + +#====================================================== +# ---> Doesn't call by top makefile, compile by local +#====================================================== +ifeq (${LOCAL_COMPILE}, YES) +ARCH?=arm920t +#ARCH?=i386 +CFLAGS+=-fPIC +TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") +ifneq (,$(filter i386,$(TMP))) + CROSS_COMPILE= +else + CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- +endif + +PRJDIR?=$(shell pwd) +CFLAGS+=-I${PRJDIR} +CC = ${CROSS_COMPILE}gcc +AR = ${CROSS_COMPILE}ar + +endif #End local compile + +ifeq ("${LINK_MODE}", "STATIC") + LIBS = ${STALIB} +else + LIBS=${DYNLIB} +endif + +all: entry ${LIBS} install + +entry: + @echo " "; + @echo " ========================================================="; + @echo " ** Compile subdir ${LIBNAME} for ${ARCH} "; + @echo " ========================================================="; + +#$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o +${STALIB}: $(OBJS) + $(AR) -rcu $@ $(OBJS) + +${DYNLIB}: $(OBJS) + $(CC) -fPIC -shared -o $@ $(OBJS) + +%.o : %.c + $(CC) -c $< $(CFLAGS) + +tag: + @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . + @cscope -Rbq + +install: + @if [ ! -z "${LIBS_PATH}" ] ; then \ + mkdir -p ${LIBS_PATH} ; \ + cp ${LIBS} ${LIBS_PATH}; \ + fi; + + +clean: + @rm -f *.o + @rm -rf *.gdb *.a *.so + +distclean: clean + @rm -f tags cscope* + +.PHONY: clean entry diff --git a/linux-bsp/asm-study/yaffs2/common/malloc.h b/linux-bsp/asm-study/yaffs2/common/malloc.h new file mode 100644 index 0000000..319438a --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/malloc.h @@ -0,0 +1,947 @@ +/* + A version of malloc/free/realloc written by Doug Lea and released to the + public domain. Send questions/comments/complaints/performance data + to dl@cs.oswego.edu + +* VERSION 2.6.6 Sun Mar 5 19:10:03 2000 Doug Lea (dl at gee) + + Note: There may be an updated version of this malloc obtainable at + ftp://g.oswego.edu/pub/misc/malloc.c + Check before installing! + +* Why use this malloc? + + This is not the fastest, most space-conserving, most portable, or + most tunable malloc ever written. However it is among the fastest + while also being among the most space-conserving, portable and tunable. + Consistent balance across these factors results in a good general-purpose + allocator. For a high-level description, see + http://g.oswego.edu/dl/html/malloc.html + +* Synopsis of public routines + + (Much fuller descriptions are contained in the program documentation below.) + + malloc(size_t n); + Return a pointer to a newly allocated chunk of at least n bytes, or null + if no space is available. + free(Void_t* p); + Release the chunk of memory pointed to by p, or no effect if p is null. + realloc(Void_t* p, size_t n); + Return a pointer to a chunk of size n that contains the same data + as does chunk p up to the minimum of (n, p's size) bytes, or null + if no space is available. The returned pointer may or may not be + the same as p. If p is null, equivalent to malloc. Unless the + #define REALLOC_ZERO_BYTES_FREES below is set, realloc with a + size argument of zero (re)allocates a minimum-sized chunk. + memalign(size_t alignment, size_t n); + Return a pointer to a newly allocated chunk of n bytes, aligned + in accord with the alignment argument, which must be a power of + two. + valloc(size_t n); + Equivalent to memalign(pagesize, n), where pagesize is the page + size of the system (or as near to this as can be figured out from + all the includes/defines below.) + pvalloc(size_t n); + Equivalent to valloc(minimum-page-that-holds(n)), that is, + round up n to nearest pagesize. + calloc(size_t unit, size_t quantity); + Returns a pointer to quantity * unit bytes, with all locations + set to zero. + cfree(Void_t* p); + Equivalent to free(p). + malloc_trim(size_t pad); + Release all but pad bytes of freed top-most memory back + to the system. Return 1 if successful, else 0. + malloc_usable_size(Void_t* p); + Report the number usable allocated bytes associated with allocated + chunk p. This may or may not report more bytes than were requested, + due to alignment and minimum size constraints. + malloc_stats(); + Prints brief summary statistics on stderr. + mallinfo() + Returns (by copy) a struct containing various summary statistics. + mallopt(int parameter_number, int parameter_value) + Changes one of the tunable parameters described below. Returns + 1 if successful in changing the parameter, else 0. + +* Vital statistics: + + Alignment: 8-byte + 8 byte alignment is currently hardwired into the design. This + seems to suffice for all current machines and C compilers. + + Assumed pointer representation: 4 or 8 bytes + Code for 8-byte pointers is untested by me but has worked + reliably by Wolfram Gloger, who contributed most of the + changes supporting this. + + Assumed size_t representation: 4 or 8 bytes + Note that size_t is allowed to be 4 bytes even if pointers are 8. + + Minimum overhead per allocated chunk: 4 or 8 bytes + Each malloced chunk has a hidden overhead of 4 bytes holding size + and status information. + + Minimum allocated size: 4-byte ptrs: 16 bytes (including 4 overhead) + 8-byte ptrs: 24/32 bytes (including, 4/8 overhead) + + When a chunk is freed, 12 (for 4byte ptrs) or 20 (for 8 byte + ptrs but 4 byte size) or 24 (for 8/8) additional bytes are + needed; 4 (8) for a trailing size field + and 8 (16) bytes for free list pointers. Thus, the minimum + allocatable size is 16/24/32 bytes. + + Even a request for zero bytes (i.e., malloc(0)) returns a + pointer to something of the minimum allocatable size. + + Maximum allocated size: 4-byte size_t: 2^31 - 8 bytes + 8-byte size_t: 2^63 - 16 bytes + + It is assumed that (possibly signed) size_t bit values suffice to + represent chunk sizes. `Possibly signed' is due to the fact + that `size_t' may be defined on a system as either a signed or + an unsigned type. To be conservative, values that would appear + as negative numbers are avoided. + Requests for sizes with a negative sign bit when the request + size is treaded as a long will return null. + + Maximum overhead wastage per allocated chunk: normally 15 bytes + + Alignnment demands, plus the minimum allocatable size restriction + make the normal worst-case wastage 15 bytes (i.e., up to 15 + more bytes will be allocated than were requested in malloc), with + two exceptions: + 1. Because requests for zero bytes allocate non-zero space, + the worst case wastage for a request of zero bytes is 24 bytes. + 2. For requests >= mmap_threshold that are serviced via + mmap(), the worst case wastage is 8 bytes plus the remainder + from a system page (the minimal mmap unit); typically 4096 bytes. + +* Limitations + + Here are some features that are NOT currently supported + + * No user-definable hooks for callbacks and the like. + * No automated mechanism for fully checking that all accesses + to malloced memory stay within their bounds. + * No support for compaction. + +* Synopsis of compile-time options: + + People have reported using previous versions of this malloc on all + versions of Unix, sometimes by tweaking some of the defines + below. It has been tested most extensively on Solaris and + Linux. It is also reported to work on WIN32 platforms. + People have also reported adapting this malloc for use in + stand-alone embedded systems. + + The implementation is in straight, hand-tuned ANSI C. Among other + consequences, it uses a lot of macros. Because of this, to be at + all usable, this code should be compiled using an optimizing compiler + (for example gcc -O2) that can simplify expressions and control + paths. + + __STD_C (default: derived from C compiler defines) + Nonzero if using ANSI-standard C compiler, a C++ compiler, or + a C compiler sufficiently close to ANSI to get away with it. + DEBUG (default: NOT defined) + Define to enable debugging. Adds fairly extensive assertion-based + checking to help track down memory errors, but noticeably slows down + execution. + REALLOC_ZERO_BYTES_FREES (default: NOT defined) + Define this if you think that realloc(p, 0) should be equivalent + to free(p). Otherwise, since malloc returns a unique pointer for + malloc(0), so does realloc(p, 0). + HAVE_MEMCPY (default: defined) + Define if you are not otherwise using ANSI STD C, but still + have memcpy and memset in your C library and want to use them. + Otherwise, simple internal versions are supplied. + USE_MEMCPY (default: 1 if HAVE_MEMCPY is defined, 0 otherwise) + Define as 1 if you want the C library versions of memset and + memcpy called in realloc and calloc (otherwise macro versions are used). + At least on some platforms, the simple macro versions usually + outperform libc versions. + HAVE_MMAP (default: defined as 1) + Define to non-zero to optionally make malloc() use mmap() to + allocate very large blocks. + HAVE_MREMAP (default: defined as 0 unless Linux libc set) + Define to non-zero to optionally make realloc() use mremap() to + reallocate very large blocks. + malloc_getpagesize (default: derived from system #includes) + Either a constant or routine call returning the system page size. + HAVE_USR_INCLUDE_MALLOC_H (default: NOT defined) + Optionally define if you are on a system with a /usr/include/malloc.h + that declares struct mallinfo. It is not at all necessary to + define this even if you do, but will ensure consistency. + INTERNAL_SIZE_T (default: size_t) + Define to a 32-bit type (probably `unsigned int') if you are on a + 64-bit machine, yet do not want or need to allow malloc requests of + greater than 2^31 to be handled. This saves space, especially for + very small chunks. + INTERNAL_LINUX_C_LIB (default: NOT defined) + Defined only when compiled as part of Linux libc. + Also note that there is some odd internal name-mangling via defines + (for example, internally, `malloc' is named `mALLOc') needed + when compiling in this case. These look funny but don't otherwise + affect anything. + WIN32 (default: undefined) + Define this on MS win (95, nt) platforms to compile in sbrk emulation. + LACKS_UNISTD_H (default: undefined if not WIN32) + Define this if your system does not have a <unistd.h>. + LACKS_SYS_PARAM_H (default: undefined if not WIN32) + Define this if your system does not have a <sys/param.h>. + MORECORE (default: sbrk) + The name of the routine to call to obtain more memory from the system. + MORECORE_FAILURE (default: -1) + The value returned upon failure of MORECORE. + MORECORE_CLEARS (default 1) + true (1) if the routine mapped to MORECORE zeroes out memory (which + holds for sbrk). + DEFAULT_TRIM_THRESHOLD + DEFAULT_TOP_PAD + DEFAULT_MMAP_THRESHOLD + DEFAULT_MMAP_MAX + Default values of tunable parameters (described in detail below) + controlling interaction with host system routines (sbrk, mmap, etc). + These values may also be changed dynamically via mallopt(). The + preset defaults are those that give best performance for typical + programs/systems. + USE_DL_PREFIX (default: undefined) + Prefix all public routines with the string 'dl'. Useful to + quickly avoid procedure declaration conflicts and linker symbol + conflicts with existing memory allocation routines. + + +*/ + + +#ifndef __MALLOC_H__ +#define __MALLOC_H__ + +/* Preliminaries */ + +#ifndef __STD_C +#ifdef __STDC__ +#define __STD_C 1 +#else +#if __cplusplus +#define __STD_C 1 +#else +#define __STD_C 0 +#endif /*__cplusplus*/ +#endif /*__STDC__*/ +#endif /*__STD_C*/ + +#ifndef Void_t +#if (__STD_C || defined(WIN32)) +#define Void_t void +#else +#define Void_t char +#endif +#endif /*Void_t*/ + +#if __STD_C +#include <types.h> /* for size_t */ +#else +#include <sys/types.h> +#endif /* __STD_C */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define assert(x) ((void)0) + +#if 0 /* not for U-Boot */ +#include <stdio.h> /* needed for malloc_stats */ +#endif + + +/* + Compile-time options +*/ + + +/* + Debugging: + + Because freed chunks may be overwritten with link fields, this + malloc will often die when freed memory is overwritten by user + programs. This can be very effective (albeit in an annoying way) + in helping track down dangling pointers. + + If you compile with -DDEBUG, a number of assertion checks are + enabled that will catch more memory errors. You probably won't be + able to make much sense of the actual assertion errors, but they + should help you locate incorrectly overwritten memory. The + checking is fairly extensive, and will slow down execution + noticeably. Calling malloc_stats or mallinfo with DEBUG set will + attempt to check every non-mmapped allocated and free chunk in the + course of computing the summmaries. (By nature, mmapped regions + cannot be checked very much automatically.) + + Setting DEBUG may also be helpful if you are trying to modify + this code. The assertions in the check routines spell out in more + detail the assumptions and invariants underlying the algorithms. + +*/ + +/* + INTERNAL_SIZE_T is the word-size used for internal bookkeeping + of chunk sizes. On a 64-bit machine, you can reduce malloc + overhead by defining INTERNAL_SIZE_T to be a 32 bit `unsigned int' + at the expense of not being able to handle requests greater than + 2^31. This limitation is hardly ever a concern; you are encouraged + to set this. However, the default version is the same as size_t. +*/ + +#ifndef INTERNAL_SIZE_T +#define INTERNAL_SIZE_T size_t +#endif + +/* + REALLOC_ZERO_BYTES_FREES should be set if a call to + realloc with zero bytes should be the same as a call to free. + Some people think it should. Otherwise, since this malloc + returns a unique pointer for malloc(0), so does realloc(p, 0). +*/ + + +/* #define REALLOC_ZERO_BYTES_FREES */ + + +/* + WIN32 causes an emulation of sbrk to be compiled in + mmap-based options are not currently supported in WIN32. +*/ + +/* #define WIN32 */ +#ifdef WIN32 +#define MORECORE wsbrk +#define HAVE_MMAP 0 + +#define LACKS_UNISTD_H +#define LACKS_SYS_PARAM_H + +/* + Include 'windows.h' to get the necessary declarations for the + Microsoft Visual C++ data structures and routines used in the 'sbrk' + emulation. + + Define WIN32_LEAN_AND_MEAN so that only the essential Microsoft + Visual C++ header files are included. +*/ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + + +/* + HAVE_MEMCPY should be defined if you are not otherwise using + ANSI STD C, but still have memcpy and memset in your C library + and want to use them in calloc and realloc. Otherwise simple + macro versions are defined here. + + USE_MEMCPY should be defined as 1 if you actually want to + have memset and memcpy called. People report that the macro + versions are often enough faster than libc versions on many + systems that it is better to use them. + +*/ + +#define HAVE_MEMCPY + +#ifndef USE_MEMCPY +#ifdef HAVE_MEMCPY +#define USE_MEMCPY 1 +#else +#define USE_MEMCPY 0 +#endif +#endif + +#if (__STD_C || defined(HAVE_MEMCPY)) + +#if __STD_C +void* memset(void*, int, size_t); +void* memcpy(void*, const void*, size_t); +#else +#ifdef WIN32 +/* On Win32 platforms, 'memset()' and 'memcpy()' are already declared in */ +/* 'windows.h' */ +#else +Void_t* memset(); +Void_t* memcpy(); +#endif +#endif +#endif + +#if USE_MEMCPY + +/* The following macros are only invoked with (2n+1)-multiples of + INTERNAL_SIZE_T units, with a positive integer n. This is exploited + for fast inline execution when n is small. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T mzsz = (nbytes); \ + if(mzsz <= 9*sizeof(mzsz)) { \ + INTERNAL_SIZE_T* mz = (INTERNAL_SIZE_T*) (charp); \ + if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; \ + if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; \ + if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \ + *mz++ = 0; }}} \ + *mz++ = 0; \ + *mz++ = 0; \ + *mz = 0; \ + } else memset((charp), 0, mzsz); \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes) \ +do { \ + INTERNAL_SIZE_T mcsz = (nbytes); \ + if(mcsz <= 9*sizeof(mcsz)) { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) (src); \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) (dest); \ + if(mcsz >= 5*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + if(mcsz >= 7*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + if(mcsz >= 9*sizeof(mcsz)) { *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; }}} \ + *mcdst++ = *mcsrc++; \ + *mcdst++ = *mcsrc++; \ + *mcdst = *mcsrc ; \ + } else memcpy(dest, src, mcsz); \ +} while(0) + +#else /* !USE_MEMCPY */ + +/* Use Duff's device for good zeroing/copying performance. */ + +#define MALLOC_ZERO(charp, nbytes) \ +do { \ + INTERNAL_SIZE_T* mzp = (INTERNAL_SIZE_T*)(charp); \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mzp++ = 0; \ + case 7: *mzp++ = 0; \ + case 6: *mzp++ = 0; \ + case 5: *mzp++ = 0; \ + case 4: *mzp++ = 0; \ + case 3: *mzp++ = 0; \ + case 2: *mzp++ = 0; \ + case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#define MALLOC_COPY(dest,src,nbytes) \ +do { \ + INTERNAL_SIZE_T* mcsrc = (INTERNAL_SIZE_T*) src; \ + INTERNAL_SIZE_T* mcdst = (INTERNAL_SIZE_T*) dest; \ + long mctmp = (nbytes)/sizeof(INTERNAL_SIZE_T), mcn; \ + if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp %= 8; } \ + switch (mctmp) { \ + case 0: for(;;) { *mcdst++ = *mcsrc++; \ + case 7: *mcdst++ = *mcsrc++; \ + case 6: *mcdst++ = *mcsrc++; \ + case 5: *mcdst++ = *mcsrc++; \ + case 4: *mcdst++ = *mcsrc++; \ + case 3: *mcdst++ = *mcsrc++; \ + case 2: *mcdst++ = *mcsrc++; \ + case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \ + } \ +} while(0) + +#endif + + +/* + Define HAVE_MMAP to optionally make malloc() use mmap() to + allocate very large blocks. These will be returned to the + operating system immediately after a free(). +*/ + +/*** +#ifndef HAVE_MMAP +#define HAVE_MMAP 1 +#endif +***/ +#undef HAVE_MMAP /* Not available for U-Boot */ + +/* + Define HAVE_MREMAP to make realloc() use mremap() to re-allocate + large blocks. This is currently only possible on Linux with + kernel versions newer than 1.3.77. +*/ + +/*** +#ifndef HAVE_MREMAP +#ifdef INTERNAL_LINUX_C_LIB +#define HAVE_MREMAP 1 +#else +#define HAVE_MREMAP 0 +#endif +#endif +***/ +#undef HAVE_MREMAP /* Not available for U-Boot */ + +#ifdef HAVE_MMAP + +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> + +#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) +#define MAP_ANONYMOUS MAP_ANON +#endif + +#endif /* HAVE_MMAP */ + +/* + Access to system page size. To the extent possible, this malloc + manages memory from the system in page-size units. + + The following mechanics for getpagesize were adapted from + bsd/gnu getpagesize.h +*/ + +#define LACKS_UNISTD_H /* Shortcut for U-Boot */ +#define malloc_getpagesize 4096 + +#ifndef LACKS_UNISTD_H +# include <unistd.h> +#endif + +#ifndef malloc_getpagesize +# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ +# ifndef _SC_PAGE_SIZE +# define _SC_PAGE_SIZE _SC_PAGESIZE +# endif +# endif +# ifdef _SC_PAGE_SIZE +# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) +# else +# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) + extern size_t getpagesize(); +# define malloc_getpagesize getpagesize() +# else +# ifdef WIN32 +# define malloc_getpagesize (4096) /* TBD: Use 'GetSystemInfo' instead */ +# else +# ifndef LACKS_SYS_PARAM_H +# include <sys/param.h> +# endif +# ifdef EXEC_PAGESIZE +# define malloc_getpagesize EXEC_PAGESIZE +# else +# ifdef NBPG +# ifndef CLSIZE +# define malloc_getpagesize NBPG +# else +# define malloc_getpagesize (NBPG * CLSIZE) +# endif +# else +# ifdef NBPC +# define malloc_getpagesize NBPC +# else +# ifdef PAGESIZE +# define malloc_getpagesize PAGESIZE +# else +# define malloc_getpagesize (4096) /* just guess */ +# endif +# endif +# endif +# endif +# endif +# endif +# endif +#endif + + +/* + + This version of malloc supports the standard SVID/XPG mallinfo + routine that returns a struct containing the same kind of + information you can get from malloc_stats. It should work on + any SVID/XPG compliant system that has a /usr/include/malloc.h + defining struct mallinfo. (If you'd like to install such a thing + yourself, cut out the preliminary declarations as described above + and below and save them in a malloc.h file. But there's no + compelling reason to bother to do this.) + + The main declaration needed is the mallinfo struct that is returned + (by-copy) by mallinfo(). The SVID/XPG malloinfo struct contains a + bunch of fields, most of which are not even meaningful in this + version of malloc. Some of these fields are are instead filled by + mallinfo() with other numbers that might possibly be of interest. + + HAVE_USR_INCLUDE_MALLOC_H should be set if you have a + /usr/include/malloc.h file that includes a declaration of struct + mallinfo. If so, it is included; else an SVID2/XPG2 compliant + version is declared below. These must be precisely the same for + mallinfo() to work. + +*/ + +/* #define HAVE_USR_INCLUDE_MALLOC_H */ + +#ifdef HAVE_USR_INCLUDE_MALLOC_H +#include "/usr/include/malloc.h" +#else + +/* SVID2/XPG mallinfo structure */ + +struct mallinfo { + int arena; /* total space allocated from system */ + int ordblks; /* number of non-inuse chunks */ + int smblks; /* unused -- always zero */ + int hblks; /* number of mmapped regions */ + int hblkhd; /* total space in mmapped regions */ + int usmblks; /* unused -- always zero */ + int fsmblks; /* unused -- always zero */ + int uordblks; /* total allocated space */ + int fordblks; /* total non-inuse space */ + int keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + +/* SVID2/XPG mallopt options */ + +#define M_MXFAST 1 /* UNUSED in this malloc */ +#define M_NLBLKS 2 /* UNUSED in this malloc */ +#define M_GRAIN 3 /* UNUSED in this malloc */ +#define M_KEEP 4 /* UNUSED in this malloc */ + +#endif + +/* mallopt options that actually do something */ + +#define M_TRIM_THRESHOLD -1 +#define M_TOP_PAD -2 +#define M_MMAP_THRESHOLD -3 +#define M_MMAP_MAX -4 + + +#ifndef DEFAULT_TRIM_THRESHOLD +#define DEFAULT_TRIM_THRESHOLD (128 * 1024) +#endif + +/* + M_TRIM_THRESHOLD is the maximum amount of unused top-most memory + to keep before releasing via malloc_trim in free(). + + Automatic trimming is mainly useful in long-lived programs. + Because trimming via sbrk can be slow on some systems, and can + sometimes be wasteful (in cases where programs immediately + afterward allocate more large chunks) the value should be high + enough so that your overall system performance would improve by + releasing. + + The trim threshold and the mmap control parameters (see below) + can be traded off with one another. Trimming and mmapping are + two different ways of releasing unused memory back to the + system. Between these two, it is often possible to keep + system-level demands of a long-lived program down to a bare + minimum. For example, in one test suite of sessions measuring + the XF86 X server on Linux, using a trim threshold of 128K and a + mmap threshold of 192K led to near-minimal long term resource + consumption. + + If you are using this malloc in a long-lived program, it should + pay to experiment with these values. As a rough guide, you + might set to a value close to the average size of a process + (program) running on your system. Releasing this much memory + would allow such a process to run in memory. Generally, it's + worth it to tune for trimming rather tham memory mapping when a + program undergoes phases where several large chunks are + allocated and released in ways that can reuse each other's + storage, perhaps mixed with phases where there are no such + chunks at all. And in well-behaved long-lived programs, + controlling release of large blocks via trimming versus mapping + is usually faster. + + However, in most programs, these parameters serve mainly as + protection against the system-level effects of carrying around + massive amounts of unneeded memory. Since frequent calls to + sbrk, mmap, and munmap otherwise degrade performance, the default + parameters are set to relatively high values that serve only as + safeguards. + + The default trim value is high enough to cause trimming only in + fairly extreme (by current memory consumption standards) cases. + It must be greater than page size to have any useful effect. To + disable trimming completely, you can set to (unsigned long)(-1); + + +*/ + + +#ifndef DEFAULT_TOP_PAD +#define DEFAULT_TOP_PAD (0) +#endif + +/* + M_TOP_PAD is the amount of extra `padding' space to allocate or + retain whenever sbrk is called. It is used in two ways internally: + + * When sbrk is called to extend the top of the arena to satisfy + a new malloc request, this much padding is added to the sbrk + request. + + * When malloc_trim is called automatically from free(), + it is used as the `pad' argument. + + In both cases, the actual amount of padding is rounded + so that the end of the arena is always a system page boundary. + + The main reason for using padding is to avoid calling sbrk so + often. Having even a small pad greatly reduces the likelihood + that nearly every malloc request during program start-up (or + after trimming) will invoke sbrk, which needlessly wastes + time. + + Automatic rounding-up to page-size units is normally sufficient + to avoid measurable overhead, so the default is 0. However, in + systems where sbrk is relatively slow, it can pay to increase + this value, at the expense of carrying around more memory than + the program needs. + +*/ + + +#ifndef DEFAULT_MMAP_THRESHOLD +#define DEFAULT_MMAP_THRESHOLD (128 * 1024) +#endif + +/* + + M_MMAP_THRESHOLD is the request size threshold for using mmap() + to service a request. Requests of at least this size that cannot + be allocated using already-existing space will be serviced via mmap. + (If enough normal freed space already exists it is used instead.) + + Using mmap segregates relatively large chunks of memory so that + they can be individually obtained and released from the host + system. A request serviced through mmap is never reused by any + other request (at least not directly; the system may just so + happen to remap successive requests to the same locations). + + Segregating space in this way has the benefit that mmapped space + can ALWAYS be individually released back to the system, which + helps keep the system level memory demands of a long-lived + program low. Mapped memory can never become `locked' between + other chunks, as can happen with normally allocated chunks, which + menas that even trimming via malloc_trim would not release them. + + However, it has the disadvantages that: + + 1. The space cannot be reclaimed, consolidated, and then + used to service later requests, as happens with normal chunks. + 2. It can lead to more wastage because of mmap page alignment + requirements + 3. It causes malloc performance to be more dependent on host + system memory management support routines which may vary in + implementation quality and may impose arbitrary + limitations. Generally, servicing a request via normal + malloc steps is faster than going through a system's mmap. + + All together, these considerations should lead you to use mmap + only for relatively large requests. + + +*/ + + +#ifndef DEFAULT_MMAP_MAX +#ifdef HAVE_MMAP +#define DEFAULT_MMAP_MAX (64) +#else +#define DEFAULT_MMAP_MAX (0) +#endif +#endif + +/* + M_MMAP_MAX is the maximum number of requests to simultaneously + service using mmap. This parameter exists because: + + 1. Some systems have a limited number of internal tables for + use by mmap. + 2. In most systems, overreliance on mmap can degrade overall + performance. + 3. If a program allocates many large regions, it is probably + better off using normal sbrk-based allocation routines that + can reclaim and reallocate normal heap memory. Using a + small value allows transition into this mode after the + first few allocations. + + Setting to 0 disables all use of mmap. If HAVE_MMAP is not set, + the default value is 0, and attempts to set it to non-zero values + in mallopt will fail. +*/ + + +/* + USE_DL_PREFIX will prefix all public routines with the string 'dl'. + Useful to quickly avoid procedure declaration conflicts and linker + symbol conflicts with existing memory allocation routines. + +*/ + +/* #define USE_DL_PREFIX */ + + +/* + + Special defines for linux libc + + Except when compiled using these special defines for Linux libc + using weak aliases, this malloc is NOT designed to work in + multithreaded applications. No semaphores or other concurrency + control are provided to ensure that multiple malloc or free calls + don't run at the same time, which could be disasterous. A single + semaphore could be used across malloc, realloc, and free (which is + essentially the effect of the linux weak alias approach). It would + be hard to obtain finer granularity. + +*/ + + +#ifdef INTERNAL_LINUX_C_LIB + +#if __STD_C + +Void_t * __default_morecore_init (ptrdiff_t); +Void_t *(*__morecore)(ptrdiff_t) = __default_morecore_init; + +#else + +Void_t * __default_morecore_init (); +Void_t *(*__morecore)() = __default_morecore_init; + +#endif + +#define MORECORE (*__morecore) +#define MORECORE_FAILURE 0 +#define MORECORE_CLEARS 1 + +#else /* INTERNAL_LINUX_C_LIB */ + +#if __STD_C +extern Void_t* sbrk(ptrdiff_t); +#else +extern Void_t* sbrk(); +#endif + +#ifndef MORECORE +#define MORECORE sbrk +#endif + +#ifndef MORECORE_FAILURE +#define MORECORE_FAILURE -1 +#endif + +#ifndef MORECORE_CLEARS +#define MORECORE_CLEARS 1 +#endif + +#endif /* INTERNAL_LINUX_C_LIB */ + +#if defined(INTERNAL_LINUX_C_LIB) && defined(__ELF__) + +#define cALLOc __libc_calloc +#define fREe __libc_free +#define mALLOc __libc_malloc +#define mEMALIGn __libc_memalign +#define rEALLOc __libc_realloc +#define vALLOc __libc_valloc +#define pvALLOc __libc_pvalloc +#define mALLINFo __libc_mallinfo +#define mALLOPt __libc_mallopt + +#pragma weak calloc = __libc_calloc +#pragma weak free = __libc_free +#pragma weak cfree = __libc_free +#pragma weak malloc = __libc_malloc +#pragma weak memalign = __libc_memalign +#pragma weak realloc = __libc_realloc +#pragma weak valloc = __libc_valloc +#pragma weak pvalloc = __libc_pvalloc +#pragma weak mallinfo = __libc_mallinfo +#pragma weak mallopt = __libc_mallopt + +#else + +#ifdef USE_DL_PREFIX +#define cALLOc dlcalloc +#define fREe dlfree +#define mALLOc dlmalloc +#define mEMALIGn dlmemalign +#define rEALLOc dlrealloc +#define vALLOc dlvalloc +#define pvALLOc dlpvalloc +#define mALLINFo dlmallinfo +#define mALLOPt dlmallopt +#else /* USE_DL_PREFIX */ +#define cALLOc calloc +#define fREe free +#define mALLOc malloc +#define mEMALIGn memalign +#define rEALLOc realloc +#define vALLOc valloc +#define pvALLOc pvalloc +#define mALLINFo mallinfo +#define mALLOPt mallopt +#endif /* USE_DL_PREFIX */ + +#endif + +/* Public routines */ + +#if __STD_C + +Void_t* mALLOc(size_t); +void fREe(Void_t*); +Void_t* rEALLOc(Void_t*, size_t); +Void_t* mEMALIGn(size_t, size_t); +Void_t* vALLOc(size_t); +Void_t* pvALLOc(size_t); +Void_t* cALLOc(size_t, size_t); +void cfree(Void_t*); +int malloc_trim(size_t); +size_t malloc_usable_size(Void_t*); +void malloc_stats(void); +int mALLOPt(int, int); +struct mallinfo mALLINFo(void); +#else +Void_t* mALLOc(); +void fREe(); +Void_t* rEALLOc(); +Void_t* mEMALIGn(); +Void_t* vALLOc(); +Void_t* pvALLOc(); +Void_t* cALLOc(); +void cfree(); +int malloc_trim(); +size_t malloc_usable_size(); +void malloc_stats(); +int mALLOPt(); +struct mallinfo mALLINFo(); +#endif + +/* + * Begin and End of memory area for malloc(), and current "brk" + */ +extern ulong mem_malloc_start; +extern ulong mem_malloc_end; +extern ulong mem_malloc_brk; + +void mem_malloc_init(ulong start, ulong size); + +#ifdef __cplusplus +}; /* end of extern "C" */ +#endif + +#endif /* __MALLOC_H__ */ diff --git a/linux-bsp/asm-study/yaffs2/common/printf.c b/linux-bsp/asm-study/yaffs2/common/printf.c new file mode 100644 index 0000000..708420c --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/printf.c @@ -0,0 +1,374 @@ +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include <stdio.h> +#include <string.h> +#include "s3c_board.h" + +#define CFG_PBSIZE 1024 /* Print Buffer Size */ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i = 0; + + while (is_digit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#ifdef CFG_64BIT_VSPRINTF +#define do_div(n,base) ({ \ + unsigned int __res; \ + __res = ((unsigned long long) n) % base; \ + n = ((unsigned long long) n) / base; \ + __res; \ +}) +#else +#define do_div(n,base) ({ \ + int __res; \ + __res = ((unsigned long) n) % base; \ + n = ((unsigned long) n) / base; \ + __res; \ +}) +#endif + +#ifdef CFG_64BIT_VSPRINTF +static char *number(char *str, long long num, unsigned int base, int size, int precision, int type) +#else +static char *number(char *str, long num, unsigned int base, int size, int precision, int type) +#endif +{ + char c, sign, tmp[66]; + const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) + { + if (num < 0) + { + sign = '-'; + num = -num; + size--; + } + else if (type & PLUS) + { + sign = '+'; + size--; + } + else if (type & SPACE) + { + sign = ' '; + size--; + } + } + if (type & SPECIAL) + { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++] = '0'; + else + while (num != 0) + tmp[i++] = digits[do_div(num, base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type & (ZEROPAD + LEFT))) + while (size-- > 0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) + { + if (base == 8) + *str++ = '0'; + else if (base == 16) + { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char *buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; +#ifdef CFG_64BIT_VSPRINTF + unsigned long long num; +#else + unsigned long num; +#endif + int i, base; + char *str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + * number of chars for from string */ + int qualifier; /* 'h', 'l', or 'q' for integer fields */ + + for (str = buf; *fmt; ++fmt) + { + if (*fmt != '%') + { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) + { + case '-': + flags |= LEFT; + goto repeat; + case '+': + flags |= PLUS; + goto repeat; + case ' ': + flags |= SPACE; + goto repeat; + case '#': + flags |= SPECIAL; + goto repeat; + case '0': + flags |= ZEROPAD; + goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) + { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') + { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') + { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || + *fmt == 'Z' || *fmt == 'z' || *fmt == 't' || *fmt == 'q') + { + qualifier = *fmt; + if (qualifier == 'l' && *(fmt + 1) == 'l') + { + qualifier = 'q'; + ++fmt; + } + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) + { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char)va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) + { + field_width = 2 * sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long)va_arg(args, void *), 16, field_width, precision, flags); + continue; + + case 'n': + if (qualifier == 'l') + { + long *ip = va_arg(args, long *); + *ip = (str - buf); + } + else + { + int *ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } +#ifdef CFG_64BIT_VSPRINTF + if (qualifier == 'q') /* "quad" for 64 bit variables */ + num = va_arg(args, unsigned long long); + else +#endif + if (qualifier == 'l') + { + num = va_arg(args, unsigned long); + } + else if (qualifier == 'Z' || qualifier == 'z') + { + num = va_arg(args, size_t); + } + else if (qualifier == 't') + { + num = va_arg(args, ptrdiff_t); + } + else if (qualifier == 'h') + { + num = (unsigned short)va_arg(args, int); + if (flags & SIGN) + num = (short)num; + } + else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str - buf; +} + +void printf(const char *fmt, ...) +{ + va_list args; + uint i; + char printbuffer[CFG_PBSIZE]; + + va_start(args, fmt); + + /* For this to work, printbuffer must be larger than + * anything we ever want to print. + */ + i = vsprintf(printbuffer, fmt, args); + va_end(args); + + console_serial_puts(printbuffer); +} + +int sprintf(char *buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i = vsprintf(buf, fmt, args); + va_end(args); + return i; +} diff --git a/linux-bsp/asm-study/yaffs2/common/stdio.h b/linux-bsp/asm-study/yaffs2/common/stdio.h new file mode 100644 index 0000000..64171b4 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/stdio.h @@ -0,0 +1,32 @@ +/******************************************************************************************** + * File: common.h + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: A busy head file + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#ifndef __COMMON_H +#define __COMMON_H + +#include <stdarg.h> +#include <types.h> + +#ifdef DEBUG +#define dbg_print(format,args...) printf(format, ##args) +#else +#define dbg_print(format,args...) do{} while(0); +#endif + +void serial_init(void); +void serial_send_byte(char c); +int serial_is_recv_enable(void); +int serial_recv_byte(void); +void serial_puts(const char *s); + +/*Define in printf.c*/ +void printf(const char *fmt, ...); +int sprintf(char *buf, const char *fmt, ...); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/common/string.c b/linux-bsp/asm-study/yaffs2/common/string.c new file mode 100644 index 0000000..46ea471 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/string.c @@ -0,0 +1,603 @@ +/* + * linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * stupid library routines.. The optimized versions should generally be found + * as inline code in <asm-xx/string.h> + * + * These are buggy as well.. + * + * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de> + * - Added strsep() which will replace strtok() soon (because strsep() is + * reentrant and should be faster). Use only strsep() in new code, please. + */ + +#include <types.h> +#include <malloc.h> + + +#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ +/** + * strnicmp - Case insensitive, length-limited string comparison + * @s1: One string + * @s2: The other string + * @len: the maximum number of characters to compare + */ +int strnicmp(const char *s1, const char *s2, size_t len) +{ + /* Yes, Virginia, it had better be unsigned */ + unsigned char c1, c2; + + c1 = 0; c2 = 0; + if (len) { + do { + c1 = *s1; c2 = *s2; + s1++; s2++; + if (!c1) + break; + if (!c2) + break; + if (c1 == c2) + continue; + c1 = tolower(c1); + c2 = tolower(c2); + if (c1 != c2) + break; + } while (--len); + } + return (int)c1 - (int)c2; +} +#endif + +char * ___strtok; + +#ifndef __HAVE_ARCH_STRCPY +/** + * strcpy - Copy a %NUL terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + */ +char * strcpy(char * dest,const char *src) +{ + char *tmp = dest; + + while ((*dest++ = *src++) != '\0') + /* nothing */; + return tmp; +} +#endif + +#ifndef __HAVE_ARCH_STRNCPY +/** + * strncpy - Copy a length-limited, %NUL-terminated string + * @dest: Where to copy the string to + * @src: Where to copy the string from + * @count: The maximum number of bytes to copy + * + * Note that unlike userspace strncpy, this does not %NUL-pad the buffer. + * However, the result is not %NUL-terminated if the source exceeds + * @count bytes. + */ +char * strncpy(char * dest,const char *src,size_t count) +{ + char *tmp = dest; + + while (count-- && (*dest++ = *src++) != '\0') + /* nothing */; + + return tmp; +} +#endif + +#ifndef __HAVE_ARCH_STRCAT +/** + * strcat - Append one %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + */ +char * strcat(char * dest, const char * src) +{ + char *tmp = dest; + + while (*dest) + dest++; + while ((*dest++ = *src++) != '\0') + ; + + return tmp; +} +#endif + +#ifndef __HAVE_ARCH_STRNCAT +/** + * strncat - Append a length-limited, %NUL-terminated string to another + * @dest: The string to be appended to + * @src: The string to append to it + * @count: The maximum numbers of bytes to copy + * + * Note that in contrast to strncpy, strncat ensures the result is + * terminated. + */ +char * strncat(char *dest, const char *src, size_t count) +{ + char *tmp = dest; + + if (count) { + while (*dest) + dest++; + while ((*dest++ = *src++)) { + if (--count == 0) { + *dest = '\0'; + break; + } + } + } + + return tmp; +} +#endif + +#ifndef __HAVE_ARCH_STRCMP +/** + * strcmp - Compare two strings + * @cs: One string + * @ct: Another string + */ +int strcmp(const char * cs,const char * ct) +{ + register signed char __res; + + while (1) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + } + + return __res; +} +#endif + +#ifndef __HAVE_ARCH_STRNCMP +/** + * strncmp - Compare two length-limited strings + * @cs: One string + * @ct: Another string + * @count: The maximum number of bytes to compare + */ +int strncmp(const char * cs,const char * ct,size_t count) +{ + register signed char __res = 0; + + while (count) { + if ((__res = *cs - *ct++) != 0 || !*cs++) + break; + count--; + } + + return __res; +} +#endif + +#ifndef __HAVE_ARCH_STRCHR +/** + * strchr - Find the first occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char * strchr(const char * s, int c) +{ + for(; *s != (char) c; ++s) + if (*s == '\0') + return NULL; + return (char *) s; +} +#endif + +#ifndef __HAVE_ARCH_STRLEN +/** + * strlen - Find the length of a string + * @s: The string to be sized + */ +size_t strlen(const char * s) +{ + const char *sc; + + for (sc = s; *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} +#endif + +#ifndef __HAVE_ARCH_STRRCHR +/** + * strrchr - Find the last occurrence of a character in a string + * @s: The string to be searched + * @c: The character to search for + */ +char * strrchr(const char * s, int c) +{ + const char *p = s + strlen(s); + do { + if (*p == (char)c) + return (char *)p; + } while (--p >= s); + return NULL; +} +#endif + +#ifndef __HAVE_ARCH_STRNLEN +/** + * strnlen - Find the length of a length-limited string + * @s: The string to be sized + * @count: The maximum number of bytes to search + */ +size_t strnlen(const char * s, size_t count) +{ + const char *sc; + + for (sc = s; count-- && *sc != '\0'; ++sc) + /* nothing */; + return sc - s; +} +#endif + +#ifndef __HAVE_ARCH_STRDUP +char * strdup(const char *s) +{ + char *new; + + if ((s == NULL) || ((new = malloc (strlen(s) + 1)) == NULL) ) + { + return NULL; + } + + strcpy (new, s); + return new; +} +#endif + +#ifndef __HAVE_ARCH_STRSPN +/** + * strspn - Calculate the length of the initial substring of @s which only + * contain letters in @accept + * @s: The string to be searched + * @accept: The string to search for + */ +size_t strspn(const char *s, const char *accept) +{ + const char *p; + const char *a; + size_t count = 0; + + for (p = s; *p != '\0'; ++p) { + for (a = accept; *a != '\0'; ++a) { + if (*p == *a) + break; + } + if (*a == '\0') + return count; + ++count; + } + + return count; +} +#endif + +#ifndef __HAVE_ARCH_STRPBRK +/** + * strpbrk - Find the first occurrence of a set of characters + * @cs: The string to be searched + * @ct: The characters to search for + */ +char * strpbrk(const char * cs,const char * ct) +{ + const char *sc1,*sc2; + + for( sc1 = cs; *sc1 != '\0'; ++sc1) { + for( sc2 = ct; *sc2 != '\0'; ++sc2) { + if (*sc1 == *sc2) + return (char *) sc1; + } + } + return NULL; +} +#endif + +#ifndef __HAVE_ARCH_STRTOK +/** + * strtok - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * WARNING: strtok is deprecated, use strsep instead. + */ +char * strtok(char * s,const char * ct) +{ + char *sbegin, *send; + + sbegin = s ? s : ___strtok; + if (!sbegin) { + return NULL; + } + sbegin += strspn(sbegin,ct); + if (*sbegin == '\0') { + ___strtok = NULL; + return( NULL ); + } + send = strpbrk( sbegin, ct); + if (send && *send != '\0') + *send++ = '\0'; + ___strtok = send; + return (sbegin); +} +#endif + +#ifndef __HAVE_ARCH_STRSEP +/** + * strsep - Split a string into tokens + * @s: The string to be searched + * @ct: The characters to search for + * + * strsep() updates @s to point after the token, ready for the next call. + * + * It returns empty tokens, too, behaving exactly like the libc function + * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. + * Same semantics, slimmer shape. ;) + */ +char * strsep(char **s, const char *ct) +{ + char *sbegin = *s, *end; + + if (sbegin == NULL) + return NULL; + + end = strpbrk(sbegin, ct); + if (end) + *end++ = '\0'; + *s = end; + + return sbegin; +} +#endif + +#ifndef __HAVE_ARCH_STRSWAB +/** + * strswab - swap adjacent even and odd bytes in %NUL-terminated string + * s: address of the string + * + * returns the address of the swapped string or NULL on error. If + * string length is odd, last byte is untouched. + */ +char *strswab(const char *s) +{ + char *p, *q; + + if ((NULL == s) || ('\0' == *s)) { + return (NULL); + } + + for (p=(char *)s, q=p+1; (*p != '\0') && (*q != '\0'); p+=2, q+=2) { + char tmp; + + tmp = *p; + *p = *q; + *q = tmp; + } + + return (char *) s; +} +#endif + +#ifndef __HAVE_ARCH_MEMSET +/** + * memset - Fill a region of memory with the given value + * @s: Pointer to the start of the area. + * @c: The byte to fill the area with + * @count: The size of the area. + * + * Do not use memset() to access IO space, use memset_io() instead. + */ +void * memset(void * s,int c,size_t count) +{ + unsigned long *sl = (unsigned long *) s; + unsigned long cl = 0; + char *s8; + int i; + + /* do it one word at a time (32 bits or 64 bits) while possible */ + if ( ((ulong)s & (sizeof(*sl) - 1)) == 0) { + for (i = 0; i < sizeof(*sl); i++) { + cl <<= 8; + cl |= c & 0xff; + } + while (count >= sizeof(*sl)) { + *sl++ = cl; + count -= sizeof(*sl); + } + } + /* fill 8 bits at a time */ + s8 = (char *)sl; + while (count--) + *s8++ = c; + + return s; +} +#endif + +#ifndef __HAVE_ARCH_BCOPY +/** + * bcopy - Copy one area of memory to another + * @src: Where to copy from + * @dest: Where to copy to + * @count: The size of the area. + * + * Note that this is the same as memcpy(), with the arguments reversed. + * memcpy() is the standard, bcopy() is a legacy BSD function. + * + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. + */ +char * bcopy(const char * src, char * dest, int count) +{ + char *tmp = dest; + + while (count--) + *tmp++ = *src++; + + return dest; +} +#endif + +#ifndef __HAVE_ARCH_MEMCPY +/** + * memcpy - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * You should not use this function to access IO space, use memcpy_toio() + * or memcpy_fromio() instead. + */ +void * memcpy(void *dest, const void *src, size_t count) +{ + unsigned long *dl = (unsigned long *)dest, *sl = (unsigned long *)src; + char *d8, *s8; + + /* while all data is aligned (common case), copy a word at a time */ + if ( (((ulong)dest | (ulong)src) & (sizeof(*dl) - 1)) == 0) { + while (count >= sizeof(*dl)) { + *dl++ = *sl++; + count -= sizeof(*dl); + } + } + /* copy the reset one byte at a time */ + d8 = (char *)dl; + s8 = (char *)sl; + while (count--) + *d8++ = *s8++; + + return dest; +} +#endif + +#ifndef __HAVE_ARCH_MEMMOVE +/** + * memmove - Copy one area of memory to another + * @dest: Where to copy to + * @src: Where to copy from + * @count: The size of the area. + * + * Unlike memcpy(), memmove() copes with overlapping areas. + */ +void * memmove(void * dest,const void *src,size_t count) +{ + char *tmp, *s; + + if (dest <= src) { + tmp = (char *) dest; + s = (char *) src; + while (count--) + *tmp++ = *s++; + } + else { + tmp = (char *) dest + count; + s = (char *) src + count; + while (count--) + *--tmp = *--s; + } + + return dest; +} +#endif + +#ifndef __HAVE_ARCH_MEMCMP +/** + * memcmp - Compare two areas of memory + * @cs: One area of memory + * @ct: Another area of memory + * @count: The size of the area. + */ +int memcmp(const void * cs,const void * ct,size_t count) +{ + const unsigned char *su1, *su2; + int res = 0; + + for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) + if ((res = *su1 - *su2) != 0) + break; + return res; +} +#endif + +#ifndef __HAVE_ARCH_MEMSCAN +/** + * memscan - Find a character in an area of memory. + * @addr: The memory area + * @c: The byte to search for + * @size: The size of the area. + * + * returns the address of the first occurrence of @c, or 1 byte past + * the area if @c is not found + */ +void * memscan(void * addr, int c, size_t size) +{ + unsigned char * p = (unsigned char *) addr; + + while (size) { + if (*p == c) + return (void *) p; + p++; + size--; + } + return (void *) p; +} +#endif + +#ifndef __HAVE_ARCH_STRSTR +/** + * strstr - Find the first substring in a %NUL terminated string + * @s1: The string to be searched + * @s2: The string to search for + */ +char * strstr(const char * s1,const char * s2) +{ + int l1, l2; + + l2 = strlen(s2); + if (!l2) + return (char *) s1; + l1 = strlen(s1); + while (l1 >= l2) { + l1--; + if (!memcmp(s1,s2,l2)) + return (char *) s1; + s1++; + } + return NULL; +} +#endif + +#ifndef __HAVE_ARCH_MEMCHR +/** + * memchr - Find a character in an area of memory. + * @s: The memory area + * @c: The byte to search for + * @n: The size of the area. + * + * returns the address of the first occurrence of @c, or %NULL + * if @c is not found + */ +void *memchr(const void *s, int c, size_t n) +{ + const unsigned char *p = s; + while (n-- != 0) { + if ((unsigned char)c == *p++) { + return (void *)(p-1); + } + } + return NULL; +} + +#endif diff --git a/linux-bsp/asm-study/yaffs2/common/string.h b/linux-bsp/asm-study/yaffs2/common/string.h new file mode 100644 index 0000000..398ca61 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/string.h @@ -0,0 +1,86 @@ +#ifndef _LINUX_STRING_H_ +#define _LINUX_STRING_H_ + +#include <types.h> /* for size_t */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern char * ___strtok; +extern char * strpbrk(const char *,const char *); +extern char * strtok(char *,const char *); +extern char * strsep(char **,const char *); +extern __kernel_size_t strspn(const char *,const char *); + + +/* + * Include machine specific inline routines + */ +#ifndef __HAVE_ARCH_STRCPY +extern char * strcpy(char *,const char *); +#endif +#ifndef __HAVE_ARCH_STRNCPY +extern char * strncpy(char *,const char *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRCAT +extern char * strcat(char *, const char *); +#endif +#ifndef __HAVE_ARCH_STRNCAT +extern char * strncat(char *, const char *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRCMP +extern int strcmp(const char *,const char *); +#endif +#ifndef __HAVE_ARCH_STRNCMP +extern int strncmp(const char *,const char *,__kernel_size_t); +#endif +#if 0 /* not used - was: #ifndef __HAVE_ARCH_STRNICMP */ +extern int strnicmp(const char *, const char *, __kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRCHR +extern char * strchr(const char *,int); +#endif +#ifndef __HAVE_ARCH_STRRCHR +extern char * strrchr(const char *,int); +#endif +#ifndef __HAVE_ARCH_STRSTR +extern char * strstr(const char *,const char *); +#endif +#ifndef __HAVE_ARCH_STRLEN +extern __kernel_size_t strlen(const char *); +#endif +#ifndef __HAVE_ARCH_STRNLEN +extern __kernel_size_t strnlen(const char *,__kernel_size_t); +#endif +#ifndef __HAVE_ARCH_STRDUP +extern char * strdup(const char *); +#endif +#ifndef __HAVE_ARCH_STRSWAB +extern char * strswab(const char *); +#endif + +#ifndef __HAVE_ARCH_MEMSET +extern void * memset(void *,int,__kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMCPY +extern void * memcpy(void *,const void *,__kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMMOVE +extern void * memmove(void *,const void *,__kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMSCAN +extern void * memscan(void *,int,__kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMCMP +extern int memcmp(const void *,const void *,__kernel_size_t); +#endif +#ifndef __HAVE_ARCH_MEMCHR +extern void * memchr(const void *,int,__kernel_size_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _LINUX_STRING_H_ */ diff --git a/linux-bsp/asm-study/yaffs2/common/types.h b/linux-bsp/asm-study/yaffs2/common/types.h new file mode 100644 index 0000000..e2fd660 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/common/types.h @@ -0,0 +1,99 @@ +#ifndef _LINUX_TYPES_H +#define _LINUX_TYPES_H + + +#undef NULL +#if defined(__cplusplus) +#define NULL 0 +#else +#define NULL ((void *)0) +#endif + +/* bsd */ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +/* sysv */ +typedef unsigned char unchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ +typedef __signed__ char __s8; +typedef unsigned char __u8; +typedef __signed__ short __s16; +typedef unsigned short __u16; +typedef __signed__ int __s32; +typedef unsigned int __u32; +#if defined(__GNUC__) +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +#endif + +typedef signed char s8; +typedef unsigned char u8; +typedef signed short s16; +typedef unsigned short u16; +typedef signed int s32; +typedef unsigned int u32; +typedef signed long long s64; +typedef unsigned long long u64; + +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_off_t; +typedef long long __kernel_loff_t; +typedef unsigned short __kernel_dev_t; +typedef unsigned short __kernel_mode_t; + + +typedef __kernel_dev_t dev_t; +typedef __kernel_mode_t mode_t; +typedef __kernel_off_t off_t; +typedef __kernel_loff_t loff_t; + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef __kernel_ptrdiff_t ptrdiff_t; +#endif + +#ifndef _SIZE_T +#define _SIZE_T +typedef __kernel_size_t size_t; +#endif + +#ifndef _SSIZE_T +#define _SSIZE_T +typedef __kernel_ssize_t ssize_t; +#endif + +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ + +typedef __u8 u_int8_t; +typedef __s8 int8_t; +typedef __u16 u_int16_t; +typedef __s16 int16_t; +typedef __u32 u_int32_t; +typedef __s32 int32_t; + +#endif /* !(__BIT_TYPES_DEFINED__) */ + +typedef __u8 uint8_t; +typedef __u16 uint16_t; +typedef __u32 uint32_t; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __u64 uint64_t; +typedef __u64 u_int64_t; +typedef __s64 int64_t; +#endif + +#endif /* _LINUX_TYPES_H */ diff --git a/linux-bsp/asm-study/yaffs2/makefile b/linux-bsp/asm-study/yaffs2/makefile new file mode 100644 index 0000000..32c2808 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/makefile @@ -0,0 +1,104 @@ + +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM source code +# * ChangeLog: 1, Release initial version on "Sun Mar 20 18:41:04 CST 2011" +# * +# *********************************************************************** +# + +APP_NAME=bootstrap +INST_PATH=/tftp +SRC_TOP=$(CURDIR) + +OBJS_MAIN := bootstrap.o start.o +OBJS_BSP += ${SRC_TOP}/bsp/*.o +OBJS_COMMON += ${SRC_TOP}/common/*.o +OBJS_YAFFS2 += ${SRC_TOP}/yaffs2/*.o + +CFLAGS+=-I${SRC_TOP}/common +CFLAGS+=-I${SRC_TOP}/bsp +CFLAGS+=-I${SRC_TOP}/yaffs2 + +# Set the stack top base address here +TEXT_BASE=0x31000000 +STACK_BASE=0x31010000 +MALLOC_SIZE=0x100000 +CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) -DSTACK_BASE=${STACK_BASE} -DCONFIG_SYS_MALLOC_LEN=${MALLOC_SIZE} + +CFLAGS+=-DDEBUG + +gccincdir := $(shell $(CC) -print-file-name=include) +CFLAGS += -ffreestanding -nostdinc -isystem $(gccincdir) -pipe +CFLAGS+= -fno-strict-aliasing -fno-common -ffixed-r8 -msoft-float +CFLAGS+=-march=armv4t -Wall -Wno-unused -Wstrict-prototypes -fno-stack-protector +CFLAGS += -fno-builtin +LDFLAGS=-Bstatic -T$(APP_NAME).lds -Ttext $(TEXT_BASE) +AFLAGS := $(CFLAGS) -D__ASSEMBLY__ +export CFLAGS +export AFLAGS + +#CFLAGS+=-Os -D__KERNEL__ -DCONFIG_ARM -D__ARM__ +PLATFORM_LIBS += -L $(shell dirname `$(CC) $(CFLAGS) -print-libgcc-file-name`) -lgcc +#PLATFORM_LIBS += -L/opt/buildroot-2011.11/arm920t/usr/arm-unknown-linux-uclibcgnueabi/sysroot/usr/lib/ -lc + +CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- +AS = $(CROSS_COMPILE)as +LD = $(CROSS_COMPILE)ld +CC = $(CROSS_COMPILE)gcc +CPP = $(CC) -E +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +LDR = $(CROSS_COMPILE)ldr +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +RANLIB = $(CROSS_COMPILE)RANLIB + +export CROSS_COMPILE AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP CFLAGS + +ALL: clean bsp_lib common_lib yaffs2_lib ${OBJS_MAIN} + echo ${OBJS_BSP} + cd $(SRC_TOP) + ${LD} $(LDFLAGS) \ + --start-group ${OBJS_BSP} ${OBJS_COMMON} ${OBJS_YAFFS2} $(OBJS_MAIN) \ + --end-group $(PLATFORM_LIBS) \ + -Map $(APP_NAME).map -o $(APP_NAME).elf + ${OBJCOPY} -O binary $(APP_NAME).elf $(APP_NAME).bin + @chmod 777 $(APP_NAME).bin + @rm -f *.elf *.o + @make install + +bsp_lib: + @make -C bsp + +common_lib: + @make -C common + +yaffs2_lib: + @make -C yaffs2 + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: $(APP_NAME).bin + cp $(APP_NAME).bin $(INST_PATH) -f + +clean: + @find $(OBJTREE) -type f \ + \( -name 'core' -o -name '*.bak' -o -name '*~' -o -name .depend \ + -o -name '*.o' -o -name '*.a' -o -name '*.elf' \) -print \ + | xargs rm -f + @rm -f $(APP_NAME).bin + @rm -f $(APP_NAME).map + @make clean -C yaffs2 + +distclean clear: clean + @rm -f cscope.* tags + + diff --git a/linux-bsp/asm-study/yaffs2/start.S b/linux-bsp/asm-study/yaffs2/start.S new file mode 100644 index 0000000..49e5040 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/start.S @@ -0,0 +1,60 @@ + +/******************************************************************************************** + * File: start.S - Startup Code for ARM920 CPU-core + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> + * Description: When system power up, the CPU will comes here to excute the first code here. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + +.globl _start +_start: b start_code + +_TEXT_BASE: + .word TEXT_BASE + +.globl _armboot_start +_armboot_start: + .word _start + +/* + * These are defined in the board-specific linker script. + */ +.globl _bss_start +_bss_start: + .word __bss_start + +.globl _bss_end +_bss_end: + .word _end + +start_code: + /* Set up the stack */ +stack_setup: + ldr r0, =TEXT_BASE /* upper 128 KiB: relocated uboot */ + sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ + sub sp, r0, #12 /* leave 3 words for abort-stack */ + bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ + +clear_bss: + ldr r0, _bss_start /* find start of bss segment */ + ldr r1, _bss_end /* stop here */ + mov r2, #0x00000000 /* clear */ + +clbss_l:str r2, [r0] /* clear loop... */ + add r0, r0, #4 + cmp r0, r1 + ble clbss_l + + bl bootstrap_main + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/makefile b/linux-bsp/asm-study/yaffs2/yaffs2/makefile new file mode 100644 index 0000000..78e9641 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/makefile @@ -0,0 +1,97 @@ +#********************************************************************************* +# Copyright: (C) 2012 CoherentPlus Sdn. Bhd. +# All rights reserved. +# +# Filename: Makefile +# Description: This is the common subdir Makefile which to compile all the C +# source code to object files and then generate the shared or +# static library named lib$(FOLDER_NAME).a orlib $(FOLDER_NAME).so, +# which depends on the variable $LINK_MODE. +# +# Version: 1.0.0(10/08/2011~) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "10/08/2011 01:29:33 AM" +# +#********************************************************************************/ + +PWD=$(shell pwd) +LOCAL_COMPILE=YES +LINK_MODE=STATIC + +#If wanna compile in the subdir, not called by top makefile, uncomment it +ifneq (${TOP_COMPILE}, YES) +LOCAL_COMPILE=YES +endif + +LIBNAME=$(shell basename ${PWD}) +STALIB=lib${LIBNAME}.a +DYNLIB=lib${LIBNAME}.so + +VPATH= . +SRCS = $(wildcard ${VPATH}/*.c) +OBJS = $(patsubst %.c,%.o,$(SRCS)) + +#====================================================== +# ---> Doesn't call by top makefile, compile by local +#====================================================== +ifeq (${LOCAL_COMPILE}, YES) +ARCH?=arm920t +#ARCH?=i386 +CFLAGS+=-fPIC +TMP=$(shell echo $(ARCH) | tr "[A-Z]" "[a-z]") +ifneq (,$(filter i386,$(TMP))) + CROSS_COMPILE= +else + CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- +endif + +PRJDIR?=$(shell pwd) +CFLAGS+=-I${PRJDIR} +CC = ${CROSS_COMPILE}gcc +AR = ${CROSS_COMPILE}ar + +endif #End local compile + +ifeq ("${LINK_MODE}", "STATIC") + LIBS = ${STALIB} +else + LIBS=${DYNLIB} +endif + +all: entry ${LIBS} install + +entry: + @echo " "; + @echo " ========================================================="; + @echo " ** Compile subdir ${LIBNAME} for ${ARCH} "; + @echo " ========================================================="; + +#$(LD) -g --relocatable $(OBJS) -o lib${LIBNAME}.o +${STALIB}: $(OBJS) + $(AR) -rcu $@ $(OBJS) + +${DYNLIB}: $(OBJS) + $(CC) -fPIC -shared -o $@ $(OBJS) + +%.o : %.c + $(CC) -c $< $(CFLAGS) + +tag: + @ctags --c-kinds=+defglmnstuvx --langmap=c:.c.h.ho.hem.het.hec.hev.him.hit.hic.hiv -R . + @cscope -Rbq + +install: + @if [ ! -z "${LIBS_PATH}" ] ; then \ + mkdir -p ${LIBS_PATH} ; \ + cp ${LIBS} ${LIBS_PATH}; \ + fi; + + +clean: + @rm -f *.o + @rm -rf *.gdb *.a *.so + +distclean: clean + @rm -f tags cscope* + +.PHONY: clean entry diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c new file mode 100644 index 0000000..c8f2861 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.c @@ -0,0 +1,357 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_allocator.h" +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yportenv.h" + +/* + * Each entry in yaffs_tnode_list and yaffs_obj_list hold blocks + * of approx 100 objects that are themn allocated singly. + * This is basically a simplified slab allocator. + * + * We don't use the Linux slab allocator because slab does not allow + * us to dump all the objects in one hit when we do a umount and tear + * down all the tnodes and objects. slab requires that we first free + * the individual objects. + * + * Once yaffs has been mainlined I shall try to motivate for a change + * to slab to provide the extra features we need here. + */ + +struct yaffs_tnode_list { + struct yaffs_tnode_list *next; + struct yaffs_tnode *tnodes; +}; + +struct yaffs_obj_list { + struct yaffs_obj_list *next; + struct yaffs_obj *objects; +}; + +struct yaffs_allocator { + int n_tnodes_created; + struct yaffs_tnode *free_tnodes; + int n_free_tnodes; + struct yaffs_tnode_list *alloc_tnode_list; + + int n_obj_created; + struct list_head free_objs; + int n_free_objects; + + struct yaffs_obj_list *allocated_obj_list; +}; + +static void yaffs_deinit_raw_tnodes(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; + struct yaffs_tnode_list *tmp; + + if (!allocator) { + BUG(); + return; + } + + while (allocator->alloc_tnode_list) { + tmp = allocator->alloc_tnode_list->next; + + kfree(allocator->alloc_tnode_list->tnodes); + kfree(allocator->alloc_tnode_list); + allocator->alloc_tnode_list = tmp; + } + + allocator->free_tnodes = NULL; + allocator->n_free_tnodes = 0; + allocator->n_tnodes_created = 0; +} + +static void yaffs_init_raw_tnodes(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + allocator->alloc_tnode_list = NULL; + allocator->free_tnodes = NULL; + allocator->n_free_tnodes = 0; + allocator->n_tnodes_created = 0; +} + +static int yaffs_create_tnodes(struct yaffs_dev *dev, int n_tnodes) +{ + struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; + int i; + struct yaffs_tnode *new_tnodes; + u8 *mem; + struct yaffs_tnode *curr; + struct yaffs_tnode *next; + struct yaffs_tnode_list *tnl; + + if (!allocator) { + BUG(); + return YAFFS_FAIL; + } + + if (n_tnodes < 1) + return YAFFS_OK; + + /* make these things */ + new_tnodes = kmalloc(n_tnodes * dev->tnode_size, GFP_NOFS); + mem = (u8 *) new_tnodes; + + if (!new_tnodes) { + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs: Could not allocate Tnodes"); + return YAFFS_FAIL; + } + + /* New hookup for wide tnodes */ + for (i = 0; i < n_tnodes - 1; i++) { + curr = (struct yaffs_tnode *)&mem[i * dev->tnode_size]; + next = (struct yaffs_tnode *)&mem[(i + 1) * dev->tnode_size]; + curr->internal[0] = next; + } + + curr = (struct yaffs_tnode *)&mem[(n_tnodes - 1) * dev->tnode_size]; + curr->internal[0] = allocator->free_tnodes; + allocator->free_tnodes = (struct yaffs_tnode *)mem; + + allocator->n_free_tnodes += n_tnodes; + allocator->n_tnodes_created += n_tnodes; + + /* Now add this bunch of tnodes to a list for freeing up. + * NB If we can't add this to the management list it isn't fatal + * but it just means we can't free this bunch of tnodes later. + */ + tnl = kmalloc(sizeof(struct yaffs_tnode_list), GFP_NOFS); + if (!tnl) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Could not add tnodes to management list"); + return YAFFS_FAIL; + } else { + tnl->tnodes = new_tnodes; + tnl->next = allocator->alloc_tnode_list; + allocator->alloc_tnode_list = tnl; + } + + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Tnodes added"); + + return YAFFS_OK; +} + +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = + (struct yaffs_allocator *)dev->allocator; + struct yaffs_tnode *tn = NULL; + + if (!allocator) { + BUG(); + return NULL; + } + + /* If there are none left make more */ + if (!allocator->free_tnodes) + yaffs_create_tnodes(dev, YAFFS_ALLOCATION_NTNODES); + + if (allocator->free_tnodes) { + tn = allocator->free_tnodes; + allocator->free_tnodes = allocator->free_tnodes->internal[0]; + allocator->n_free_tnodes--; + } + + return tn; +} + +/* FreeTnode frees up a tnode and puts it back on the free list */ +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +{ + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + if (tn) { + tn->internal[0] = allocator->free_tnodes; + allocator->free_tnodes = tn; + allocator->n_free_tnodes++; + } + dev->checkpoint_blocks_required = 0; /* force recalculation */ +} + +/*--------------- yaffs_obj alloaction ------------------------ + * + * Free yaffs_objs are stored in a list using obj->siblings. + * The blocks of allocated objects are stored in a linked list. + */ + +static void yaffs_init_raw_objs(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + allocator->allocated_obj_list = NULL; + INIT_LIST_HEAD(&allocator->free_objs); + allocator->n_free_objects = 0; +} + +static void yaffs_deinit_raw_objs(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator = dev->allocator; + struct yaffs_obj_list *tmp; + + if (!allocator) { + BUG(); + return; + } + + while (allocator->allocated_obj_list) { + tmp = allocator->allocated_obj_list->next; + kfree(allocator->allocated_obj_list->objects); + kfree(allocator->allocated_obj_list); + allocator->allocated_obj_list = tmp; + } + + INIT_LIST_HEAD(&allocator->free_objs); + allocator->n_free_objects = 0; + allocator->n_obj_created = 0; +} + +static int yaffs_create_free_objs(struct yaffs_dev *dev, int n_obj) +{ + struct yaffs_allocator *allocator = dev->allocator; + int i; + struct yaffs_obj *new_objs; + struct yaffs_obj_list *list; + + if (!allocator) { + BUG(); + return YAFFS_FAIL; + } + + if (n_obj < 1) + return YAFFS_OK; + + /* make these things */ + new_objs = kmalloc(n_obj * sizeof(struct yaffs_obj), GFP_NOFS); + list = kmalloc(sizeof(struct yaffs_obj_list), GFP_NOFS); + + if (!new_objs || !list) { + kfree(new_objs); + new_objs = NULL; + kfree(list); + list = NULL; + yaffs_trace(YAFFS_TRACE_ALLOCATE, + "Could not allocate more objects"); + return YAFFS_FAIL; + } + + /* Hook them into the free list */ + for (i = 0; i < n_obj; i++) + list_add(&new_objs[i].siblings, &allocator->free_objs); + + allocator->n_free_objects += n_obj; + allocator->n_obj_created += n_obj; + + /* Now add this bunch of Objects to a list for freeing up. */ + + list->objects = new_objs; + list->next = allocator->allocated_obj_list; + allocator->allocated_obj_list = list; + + return YAFFS_OK; +} + +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj = NULL; + struct list_head *lh; + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return obj; + } + + /* If there are none left make more */ + if (list_empty(&allocator->free_objs)) + yaffs_create_free_objs(dev, YAFFS_ALLOCATION_NOBJECTS); + + if (!list_empty(&allocator->free_objs)) { + lh = allocator->free_objs.next; + obj = list_entry(lh, struct yaffs_obj, siblings); + list_del_init(lh); + allocator->n_free_objects--; + } + + return obj; +} + +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj) +{ + + struct yaffs_allocator *allocator = dev->allocator; + + if (!allocator) { + BUG(); + return; + } + + /* Link into the free list. */ + list_add(&obj->siblings, &allocator->free_objs); + allocator->n_free_objects++; +} + +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev) +{ + + if (!dev->allocator) { + BUG(); + return; + } + + yaffs_deinit_raw_tnodes(dev); + yaffs_deinit_raw_objs(dev); + kfree(dev->allocator); + dev->allocator = NULL; +} + +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev) +{ + struct yaffs_allocator *allocator; + + if (dev->allocator) { + BUG(); + return; + } + + allocator = kmalloc(sizeof(struct yaffs_allocator), GFP_NOFS); + if (allocator) { + dev->allocator = allocator; + yaffs_init_raw_tnodes(dev); + yaffs_init_raw_objs(dev); + } +} + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h new file mode 100644 index 0000000..a8cc322 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_allocator.h @@ -0,0 +1,30 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_ALLOCATOR_H__ +#define __YAFFS_ALLOCATOR_H__ + +#include "yaffs_guts.h" + +void yaffs_init_raw_tnodes_and_objs(struct yaffs_dev *dev); +void yaffs_deinit_raw_tnodes_and_objs(struct yaffs_dev *dev); + +struct yaffs_tnode *yaffs_alloc_raw_tnode(struct yaffs_dev *dev); +void yaffs_free_raw_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn); + +struct yaffs_obj *yaffs_alloc_raw_obj(struct yaffs_dev *dev); +void yaffs_free_raw_obj(struct yaffs_dev *dev, struct yaffs_obj *obj); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c new file mode 100644 index 0000000..3d778f2 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.c @@ -0,0 +1,124 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_guts.h" +#include "yaffs_attribs.h" + +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh) +{ + obj->yst_uid = oh->yst_uid; + obj->yst_gid = oh->yst_gid; + obj->yst_atime = oh->yst_atime; + obj->yst_mtime = oh->yst_mtime; + obj->yst_ctime = oh->yst_ctime; + obj->yst_rdev = oh->yst_rdev; +} + +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj) +{ + oh->yst_uid = obj->yst_uid; + oh->yst_gid = obj->yst_gid; + oh->yst_atime = obj->yst_atime; + oh->yst_mtime = obj->yst_mtime; + oh->yst_ctime = obj->yst_ctime; + oh->yst_rdev = obj->yst_rdev; + +} + +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c) +{ + obj->yst_mtime = Y_CURRENT_TIME; + if (do_a) + obj->yst_atime = obj->yst_mtime; + if (do_c) + obj->yst_ctime = obj->yst_mtime; +} + +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev) +{ + yaffs_load_current_time(obj, 1, 1); + obj->yst_rdev = rdev; + obj->yst_uid = uid; + obj->yst_gid = gid; +} + +static loff_t yaffs_get_file_size(struct yaffs_obj *obj) +{ + YCHAR *alias = NULL; + obj = yaffs_get_equivalent_obj(obj); + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + return obj->variant.file_variant.file_size; + case YAFFS_OBJECT_TYPE_SYMLINK: + alias = obj->variant.symlink_variant.alias; + if (!alias) + return 0; + return strnlen(alias, YAFFS_MAX_ALIAS_LENGTH); + default: + return 0; + } +} + +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr) +{ + unsigned int valid = attr->ia_valid; + + if (valid & ATTR_MODE) + obj->yst_mode = attr->ia_mode; + if (valid & ATTR_UID) + obj->yst_uid = attr->ia_uid; + if (valid & ATTR_GID) + obj->yst_gid = attr->ia_gid; + + if (valid & ATTR_ATIME) + obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime); + if (valid & ATTR_CTIME) + obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime); + if (valid & ATTR_MTIME) + obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime); + + if (valid & ATTR_SIZE) + yaffs_resize_file(obj, attr->ia_size); + + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); + + return YAFFS_OK; + +} + +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr) +{ + unsigned int valid = 0; + + attr->ia_mode = obj->yst_mode; + valid |= ATTR_MODE; + attr->ia_uid = obj->yst_uid; + valid |= ATTR_UID; + attr->ia_gid = obj->yst_gid; + valid |= ATTR_GID; + + Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime; + valid |= ATTR_ATIME; + Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime; + valid |= ATTR_CTIME; + Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime; + valid |= ATTR_MTIME; + + attr->ia_size = yaffs_get_file_size(obj); + valid |= ATTR_SIZE; + + attr->ia_valid = valid; + + return YAFFS_OK; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h new file mode 100644 index 0000000..5b21b08 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_attribs.h @@ -0,0 +1,28 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_ATTRIBS_H__ +#define __YAFFS_ATTRIBS_H__ + +#include "yaffs_guts.h" + +void yaffs_load_attribs(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh); +void yaffs_load_attribs_oh(struct yaffs_obj_hdr *oh, struct yaffs_obj *obj); +void yaffs_attribs_init(struct yaffs_obj *obj, u32 gid, u32 uid, u32 rdev); +void yaffs_load_current_time(struct yaffs_obj *obj, int do_a, int do_c); +int yaffs_set_attribs(struct yaffs_obj *obj, struct iattr *attr); +int yaffs_get_attribs(struct yaffs_obj *obj, struct iattr *attr); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c new file mode 100644 index 0000000..4440e93 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.c @@ -0,0 +1,97 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_bitmap.h" +#include "yaffs_trace.h" +/* + * Chunk bitmap manipulations + */ + +static inline u8 *yaffs_block_bits(struct yaffs_dev *dev, int blk) +{ + if (blk < dev->internal_start_block || blk > dev->internal_end_block) { + yaffs_trace(YAFFS_TRACE_ERROR, + "BlockBits block %d is not valid", + blk); + BUG(); + } + return dev->chunk_bits + + (dev->chunk_bit_stride * (blk - dev->internal_start_block)); +} + +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk) +{ + if (blk < dev->internal_start_block || blk > dev->internal_end_block || + chunk < 0 || chunk >= dev->param.chunks_per_block) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Chunk Id (%d:%d) invalid", + blk, chunk); + BUG(); + } +} + +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + memset(blk_bits, 0, dev->chunk_bit_stride); +} + +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + yaffs_verify_chunk_bit_id(dev, blk, chunk); + blk_bits[chunk / 8] &= ~(1 << (chunk & 7)); +} + +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + yaffs_verify_chunk_bit_id(dev, blk, chunk); + blk_bits[chunk / 8] |= (1 << (chunk & 7)); +} + +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + + yaffs_verify_chunk_bit_id(dev, blk, chunk); + return (blk_bits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0; +} + +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + int i; + + for (i = 0; i < dev->chunk_bit_stride; i++) { + if (*blk_bits) + return 1; + blk_bits++; + } + return 0; +} + +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk) +{ + u8 *blk_bits = yaffs_block_bits(dev, blk); + int i; + int n = 0; + + for (i = 0; i < dev->chunk_bit_stride; i++, blk_bits++) + n += hweight8(*blk_bits); + + return n; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h new file mode 100644 index 0000000..e26b37d --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_bitmap.h @@ -0,0 +1,33 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * Chunk bitmap manipulations + */ + +#ifndef __YAFFS_BITMAP_H__ +#define __YAFFS_BITMAP_H__ + +#include "yaffs_guts.h" + +void yaffs_verify_chunk_bit_id(struct yaffs_dev *dev, int blk, int chunk); +void yaffs_clear_chunk_bits(struct yaffs_dev *dev, int blk); +void yaffs_clear_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +void yaffs_set_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +int yaffs_check_chunk_bit(struct yaffs_dev *dev, int blk, int chunk); +int yaffs_still_some_chunks(struct yaffs_dev *dev, int blk); +int yaffs_count_chunk_bits(struct yaffs_dev *dev, int blk); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c new file mode 100644 index 0000000..8478eb8 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.c @@ -0,0 +1,473 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_checkptrw.h" +#include "yaffs_getblockinfo.h" + +struct yaffs_checkpt_chunk_hdr { + int version; + int seq; + u32 sum; + u32 xor; +} ; + + +static int apply_chunk_offset(struct yaffs_dev *dev, int chunk) +{ + return chunk - dev->chunk_offset; +} + +static int apply_block_offset(struct yaffs_dev *dev, int block) +{ + return block - dev->block_offset; +} + +static void yaffs2_checkpt_init_chunk_hdr(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_chunk_hdr hdr; + + hdr.version = YAFFS_CHECKPOINT_VERSION; + hdr.seq = dev->checkpt_page_seq; + hdr.sum = dev->checkpt_sum; + hdr.xor = dev->checkpt_xor; + + dev->checkpt_byte_offs = sizeof(hdr); + + memcpy(dev->checkpt_buffer, &hdr, sizeof(hdr)); +} + +static int yaffs2_checkpt_check_chunk_hdr(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_chunk_hdr hdr; + + memcpy(&hdr, dev->checkpt_buffer, sizeof(hdr)); + + dev->checkpt_byte_offs = sizeof(hdr); + + return hdr.version == YAFFS_CHECKPOINT_VERSION && + hdr.seq == dev->checkpt_page_seq && + hdr.sum == dev->checkpt_sum && + hdr.xor == dev->checkpt_xor; +} + +static int yaffs2_checkpt_space_ok(struct yaffs_dev *dev) +{ + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checkpt blocks_avail = %d", blocks_avail); + + return (blocks_avail <= 0) ? 0 : 1; +} + +static int yaffs_checkpt_erase(struct yaffs_dev *dev) +{ + int i; + + if (!dev->param.erase_fn) + return 0; + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checking blocks %d to %d", + dev->internal_start_block, dev->internal_end_block); + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); + int offset_i = apply_block_offset(dev, i); + int result; + + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "erasing checkpt block %d", i); + + dev->n_erasures++; + + result = dev->param.erase_fn(dev, offset_i); + if(result) { + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; + dev->n_erased_blocks++; + dev->n_free_chunks += + dev->param.chunks_per_block; + } else { + dev->param.bad_block_fn(dev, offset_i); + bi->block_state = YAFFS_BLOCK_STATE_DEAD; + } + } + } + + dev->blocks_in_checkpt = 0; + + return 1; +} + +static void yaffs2_checkpt_find_erased_block(struct yaffs_dev *dev) +{ + int i; + int blocks_avail = dev->n_erased_blocks - dev->param.n_reserved_blocks; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "allocating checkpt block: erased %d reserved %d avail %d next %d ", + dev->n_erased_blocks, dev->param.n_reserved_blocks, + blocks_avail, dev->checkpt_next_block); + + if (dev->checkpt_next_block >= 0 && + dev->checkpt_next_block <= dev->internal_end_block && + blocks_avail > 0) { + + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { + struct yaffs_block_info *bi; + + bi = yaffs_get_block_info(dev, i); + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { + dev->checkpt_next_block = i + 1; + dev->checkpt_cur_block = i; + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "allocating checkpt block %d", i); + return; + } + } + } + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "out of checkpt blocks"); + + dev->checkpt_next_block = -1; + dev->checkpt_cur_block = -1; +} + +static void yaffs2_checkpt_find_block(struct yaffs_dev *dev) +{ + int i; + struct yaffs_ext_tags tags; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "find next checkpt block: start: blocks %d next %d", + dev->blocks_in_checkpt, dev->checkpt_next_block); + + if (dev->blocks_in_checkpt < dev->checkpt_max_blocks) + for (i = dev->checkpt_next_block; i <= dev->internal_end_block; + i++) { + int chunk = i * dev->param.chunks_per_block; + enum yaffs_block_state state; + u32 seq; + + dev->param.read_chunk_tags_fn(dev, + apply_chunk_offset(dev, chunk), + NULL, &tags); + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "find next checkpt block: search: block %d state %d oid %d seq %d eccr %d", + i, (int) state, + tags.obj_id, tags.seq_number, + tags.ecc_result); + + if (tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) + continue; + + dev->param.query_block_fn(dev, + apply_block_offset(dev, i), + &state, &seq); + if (state == YAFFS_BLOCK_STATE_DEAD) + continue; + + /* Right kind of block */ + dev->checkpt_next_block = tags.obj_id; + dev->checkpt_cur_block = i; + dev->checkpt_block_list[dev->blocks_in_checkpt] = i; + dev->blocks_in_checkpt++; + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "found checkpt block %d", i); + return; + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "found no more checkpt blocks"); + + dev->checkpt_next_block = -1; + dev->checkpt_cur_block = -1; +} + +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing) +{ + int i; + + dev->checkpt_open_write = writing; + + /* Got the functions we need? */ + if (!dev->param.write_chunk_tags_fn || + !dev->param.read_chunk_tags_fn || + !dev->param.erase_fn || !dev->param.bad_block_fn) + return 0; + + if (writing && !yaffs2_checkpt_space_ok(dev)) + return 0; + + if (!dev->checkpt_buffer) + dev->checkpt_buffer = + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); + if (!dev->checkpt_buffer) + return 0; + + dev->checkpt_page_seq = 0; + dev->checkpt_byte_count = 0; + dev->checkpt_sum = 0; + dev->checkpt_xor = 0; + dev->checkpt_cur_block = -1; + dev->checkpt_cur_chunk = -1; + dev->checkpt_next_block = dev->internal_start_block; + + if (writing) { + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); + yaffs2_checkpt_init_chunk_hdr(dev); + return yaffs_checkpt_erase(dev); + } + + /* Opening for a read */ + /* Set to a value that will kick off a read */ + dev->checkpt_byte_offs = dev->data_bytes_per_chunk; + /* A checkpoint block list of 1 checkpoint block per 16 block is + * (hopefully) going to be way more than we need */ + dev->blocks_in_checkpt = 0; + dev->checkpt_max_blocks = + (dev->internal_end_block - dev->internal_start_block) / 16 + 2; + dev->checkpt_block_list = + kmalloc(sizeof(int) * dev->checkpt_max_blocks, GFP_NOFS); + + if (!dev->checkpt_block_list) + return 0; + + for (i = 0; i < dev->checkpt_max_blocks; i++) + dev->checkpt_block_list[i] = -1; + + return 1; +} + +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum) +{ + u32 composite_sum; + + composite_sum = (dev->checkpt_sum << 8) | (dev->checkpt_xor & 0xff); + *sum = composite_sum; + return 1; +} + +static int yaffs2_checkpt_flush_buffer(struct yaffs_dev *dev) +{ + int chunk; + int offset_chunk; + struct yaffs_ext_tags tags; + + if (dev->checkpt_cur_block < 0) { + yaffs2_checkpt_find_erased_block(dev); + dev->checkpt_cur_chunk = 0; + } + + if (dev->checkpt_cur_block < 0) + return 0; + + tags.is_deleted = 0; + tags.obj_id = dev->checkpt_next_block; /* Hint to next place to look */ + tags.chunk_id = dev->checkpt_page_seq + 1; + tags.seq_number = YAFFS_SEQUENCE_CHECKPOINT_DATA; + tags.n_bytes = dev->data_bytes_per_chunk; + if (dev->checkpt_cur_chunk == 0) { + /* First chunk we write for the block? Set block state to + checkpoint */ + struct yaffs_block_info *bi = + yaffs_get_block_info(dev, dev->checkpt_cur_block); + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; + dev->blocks_in_checkpt++; + } + + chunk = + dev->checkpt_cur_block * dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checkpoint wite buffer nand %d(%d:%d) objid %d chId %d", + chunk, dev->checkpt_cur_block, dev->checkpt_cur_chunk, + tags.obj_id, tags.chunk_id); + + offset_chunk = apply_chunk_offset(dev, chunk); + + dev->n_page_writes++; + + dev->param.write_chunk_tags_fn(dev, offset_chunk, + dev->checkpt_buffer, &tags); + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; + if (dev->checkpt_cur_chunk >= dev->param.chunks_per_block) { + dev->checkpt_cur_chunk = 0; + dev->checkpt_cur_block = -1; + } + memset(dev->checkpt_buffer, 0, dev->data_bytes_per_chunk); + + yaffs2_checkpt_init_chunk_hdr(dev); + + + return 1; +} + +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes) +{ + int i = 0; + int ok = 1; + u8 *data_bytes = (u8 *) data; + + if (!dev->checkpt_buffer) + return 0; + + if (!dev->checkpt_open_write) + return -1; + + while (i < n_bytes && ok) { + dev->checkpt_buffer[dev->checkpt_byte_offs] = *data_bytes; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + + if (dev->checkpt_byte_offs < 0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) + ok = yaffs2_checkpt_flush_buffer(dev); + } + + return i; +} + +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes) +{ + int i = 0; + int ok = 1; + struct yaffs_ext_tags tags; + int chunk; + int offset_chunk; + u8 *data_bytes = (u8 *) data; + + if (!dev->checkpt_buffer) + return 0; + + if (dev->checkpt_open_write) + return -1; + + while (i < n_bytes && ok) { + + if (dev->checkpt_byte_offs < 0 || + dev->checkpt_byte_offs >= dev->data_bytes_per_chunk) { + + if (dev->checkpt_cur_block < 0) { + yaffs2_checkpt_find_block(dev); + dev->checkpt_cur_chunk = 0; + } + + if (dev->checkpt_cur_block < 0) { + ok = 0; + break; + } + + chunk = dev->checkpt_cur_block * + dev->param.chunks_per_block + + dev->checkpt_cur_chunk; + + offset_chunk = apply_chunk_offset(dev, chunk); + dev->n_page_reads++; + + /* read in the next chunk */ + dev->param.read_chunk_tags_fn(dev, + offset_chunk, + dev->checkpt_buffer, + &tags); + + if (tags.chunk_id != (dev->checkpt_page_seq + 1) || + tags.ecc_result > YAFFS_ECC_RESULT_FIXED || + tags.seq_number != YAFFS_SEQUENCE_CHECKPOINT_DATA) { + ok = 0; + break; + } + if(!yaffs2_checkpt_check_chunk_hdr(dev)) { + ok = 0; + break; + } + + dev->checkpt_page_seq++; + dev->checkpt_cur_chunk++; + + if (dev->checkpt_cur_chunk >= + dev->param.chunks_per_block) + dev->checkpt_cur_block = -1; + + } + + *data_bytes = dev->checkpt_buffer[dev->checkpt_byte_offs]; + dev->checkpt_sum += *data_bytes; + dev->checkpt_xor ^= *data_bytes; + dev->checkpt_byte_offs++; + i++; + data_bytes++; + dev->checkpt_byte_count++; + } + + return i; +} + +int yaffs_checkpt_close(struct yaffs_dev *dev) +{ + int i; + + if (dev->checkpt_open_write) { + if (dev->checkpt_byte_offs != + sizeof(sizeof(struct yaffs_checkpt_chunk_hdr))) + yaffs2_checkpt_flush_buffer(dev); + } else if (dev->checkpt_block_list) { + for (i = 0; + i < dev->blocks_in_checkpt && + dev->checkpt_block_list[i] >= 0; i++) { + int blk = dev->checkpt_block_list[i]; + struct yaffs_block_info *bi = NULL; + + if (dev->internal_start_block <= blk && + blk <= dev->internal_end_block) + bi = yaffs_get_block_info(dev, blk); + if (bi && bi->block_state == YAFFS_BLOCK_STATE_EMPTY) + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; + } + kfree(dev->checkpt_block_list); + dev->checkpt_block_list = NULL; + } + + dev->n_free_chunks -= + dev->blocks_in_checkpt * dev->param.chunks_per_block; + dev->n_erased_blocks -= dev->blocks_in_checkpt; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, "checkpoint byte count %d", + dev->checkpt_byte_count); + + if (dev->checkpt_buffer) { + /* free the buffer */ + kfree(dev->checkpt_buffer); + dev->checkpt_buffer = NULL; + return 1; + } else { + return 0; + } +} + +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev) +{ + /* Erase the checkpoint data */ + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "checkpoint invalidate of %d blocks", + dev->blocks_in_checkpt); + + return yaffs_checkpt_erase(dev); +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h new file mode 100644 index 0000000..cdbaba7 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_checkptrw.h @@ -0,0 +1,33 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_CHECKPTRW_H__ +#define __YAFFS_CHECKPTRW_H__ + +#include "yaffs_guts.h" + +int yaffs2_checkpt_open(struct yaffs_dev *dev, int writing); + +int yaffs2_checkpt_wr(struct yaffs_dev *dev, const void *data, int n_bytes); + +int yaffs2_checkpt_rd(struct yaffs_dev *dev, void *data, int n_bytes); + +int yaffs2_get_checkpt_sum(struct yaffs_dev *dev, u32 * sum); + +int yaffs_checkpt_close(struct yaffs_dev *dev); + +int yaffs2_checkpt_invalidate_stream(struct yaffs_dev *dev); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c new file mode 100644 index 0000000..9294107 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.c @@ -0,0 +1,281 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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 code implements the ECC algorithm used in SmartMedia. + * + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The two unused bit are set to 1. + * The ECC can correct single bit errors in a 256-byte page of data. Thus, two + * such ECC blocks are used on a 512-byte NAND page. + * + */ + +#include "yportenv.h" + +#include "yaffs_ecc.h" + +/* Table generated by gen-ecc.c + * Using a table means we do not have to calculate p1..p4 and p1'..p4' + * for each byte of data. These are instead provided in a table in bits7..2. + * Bit 0 of each entry indicates whether the entry has an odd or even parity, + * and therefore this bytes influence on the line parity. + */ + +static const unsigned char column_parity_table[] = { + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0, + 0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9, + 0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55, + 0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c, + 0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59, + 0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30, + 0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc, + 0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5, + 0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65, + 0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c, + 0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0, + 0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99, + 0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc, + 0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95, + 0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69, + 0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00, +}; + + +/* Calculate the ECC for a 256-byte block of data */ +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc) +{ + unsigned int i; + unsigned char col_parity = 0; + unsigned char line_parity = 0; + unsigned char line_parity_prime = 0; + unsigned char t; + unsigned char b; + + for (i = 0; i < 256; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + + if (b & 0x01) { /* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + } + + ecc[2] = (~col_parity) | 0x03; + + t = 0; + if (line_parity & 0x80) + t |= 0x80; + if (line_parity_prime & 0x80) + t |= 0x40; + if (line_parity & 0x40) + t |= 0x20; + if (line_parity_prime & 0x40) + t |= 0x10; + if (line_parity & 0x20) + t |= 0x08; + if (line_parity_prime & 0x20) + t |= 0x04; + if (line_parity & 0x10) + t |= 0x02; + if (line_parity_prime & 0x10) + t |= 0x01; + ecc[1] = ~t; + + t = 0; + if (line_parity & 0x08) + t |= 0x80; + if (line_parity_prime & 0x08) + t |= 0x40; + if (line_parity & 0x04) + t |= 0x20; + if (line_parity_prime & 0x04) + t |= 0x10; + if (line_parity & 0x02) + t |= 0x08; + if (line_parity_prime & 0x02) + t |= 0x04; + if (line_parity & 0x01) + t |= 0x02; + if (line_parity_prime & 0x01) + t |= 0x01; + ecc[0] = ~t; + +} + +/* Correct the ECC on a 256 byte block of data */ + +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, + const unsigned char *test_ecc) +{ + unsigned char d0, d1, d2; /* deltas */ + + d0 = read_ecc[0] ^ test_ecc[0]; + d1 = read_ecc[1] ^ test_ecc[1]; + d2 = read_ecc[2] ^ test_ecc[2]; + + if ((d0 | d1 | d2) == 0) + return 0; /* no error */ + + if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 && + ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 && + ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) { + /* Single bit (recoverable) error in data */ + + unsigned byte; + unsigned bit; + + bit = byte = 0; + + if (d1 & 0x80) + byte |= 0x80; + if (d1 & 0x20) + byte |= 0x40; + if (d1 & 0x08) + byte |= 0x20; + if (d1 & 0x02) + byte |= 0x10; + if (d0 & 0x80) + byte |= 0x08; + if (d0 & 0x20) + byte |= 0x04; + if (d0 & 0x08) + byte |= 0x02; + if (d0 & 0x02) + byte |= 0x01; + + if (d2 & 0x80) + bit |= 0x04; + if (d2 & 0x20) + bit |= 0x02; + if (d2 & 0x08) + bit |= 0x01; + + data[byte] ^= (1 << bit); + + return 1; /* Corrected the error */ + } + + if ((hweight8(d0) + hweight8(d1) + hweight8(d2)) == 1) { + /* Reccoverable error in ecc */ + + read_ecc[0] = test_ecc[0]; + read_ecc[1] = test_ecc[1]; + read_ecc[2] = test_ecc[2]; + + return 1; /* Corrected the error */ + } + + /* Unrecoverable error */ + + return -1; + +} + +/* + * ECCxxxOther does ECC calcs on arbitrary n bytes of data + */ +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *ecc_other) +{ + unsigned int i; + unsigned char col_parity = 0; + unsigned line_parity = 0; + unsigned line_parity_prime = 0; + unsigned char b; + + for (i = 0; i < n_bytes; i++) { + b = column_parity_table[*data++]; + col_parity ^= b; + + if (b & 0x01) { + /* odd number of bits in the byte */ + line_parity ^= i; + line_parity_prime ^= ~i; + } + + } + + ecc_other->col_parity = (col_parity >> 2) & 0x3f; + ecc_other->line_parity = line_parity; + ecc_other->line_parity_prime = line_parity_prime; +} + +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *read_ecc, + const struct yaffs_ecc_other *test_ecc) +{ + unsigned char delta_col; /* column parity delta */ + unsigned delta_line; /* line parity delta */ + unsigned delta_line_prime; /* line parity delta */ + unsigned bit; + + delta_col = read_ecc->col_parity ^ test_ecc->col_parity; + delta_line = read_ecc->line_parity ^ test_ecc->line_parity; + delta_line_prime = + read_ecc->line_parity_prime ^ test_ecc->line_parity_prime; + + if ((delta_col | delta_line | delta_line_prime) == 0) + return 0; /* no error */ + + if (delta_line == ~delta_line_prime && + (((delta_col ^ (delta_col >> 1)) & 0x15) == 0x15)) { + /* Single bit (recoverable) error in data */ + + bit = 0; + + if (delta_col & 0x20) + bit |= 0x04; + if (delta_col & 0x08) + bit |= 0x02; + if (delta_col & 0x02) + bit |= 0x01; + + if (delta_line >= n_bytes) + return -1; + + data[delta_line] ^= (1 << bit); + + return 1; /* corrected */ + } + + if ((hweight32(delta_line) + + hweight32(delta_line_prime) + + hweight8(delta_col)) == 1) { + /* Reccoverable error in ecc */ + + *read_ecc = *test_ecc; + return 1; /* corrected */ + } + + /* Unrecoverable error */ + + return -1; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h new file mode 100644 index 0000000..17d47bd --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_ecc.h @@ -0,0 +1,44 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * This code implements the ECC algorithm used in SmartMedia. + * + * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes. + * The two unused bit are set to 1. + * The ECC can correct single bit errors in a 256-byte page of data. + * Thus, two such ECC blocks are used on a 512-byte NAND page. + * + */ + +#ifndef __YAFFS_ECC_H__ +#define __YAFFS_ECC_H__ + +struct yaffs_ecc_other { + unsigned char col_parity; + unsigned line_parity; + unsigned line_parity_prime; +}; + +void yaffs_ecc_calc(const unsigned char *data, unsigned char *ecc); +int yaffs_ecc_correct(unsigned char *data, unsigned char *read_ecc, + const unsigned char *test_ecc); + +void yaffs_ecc_calc_other(const unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *ecc); +int yaffs_ecc_correct_other(unsigned char *data, unsigned n_bytes, + struct yaffs_ecc_other *read_ecc, + const struct yaffs_ecc_other *test_ecc); +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c new file mode 100644 index 0000000..11b75f7 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_error.c @@ -0,0 +1,58 @@ +/* + * YAFFS: Yet another FFS. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Timothy Manning <timothy@yaffs.net> + * + * 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. + */ + +#include "yaffsfs.h" + +struct error_entry { + int code; + const char *text; +}; + +static const struct error_entry error_list[] = { + { ENOMEM , "ENOMEM" }, + { EBUSY , "EBUSY"}, + { ENODEV , "ENODEV"}, + { EINVAL , "EINVAL"}, + { EBADF , "EBADF"}, + { EACCES , "EACCES"}, + { EXDEV , "EXDEV" }, + { ENOENT , "ENOENT"}, + { ENOSPC , "ENOSPC"}, + { ERANGE , "ERANGE"}, + { ENODATA, "ENODATA"}, + { ENOTEMPTY, "ENOTEMPTY"}, + { ENAMETOOLONG, "ENAMETOOLONG"}, + { ENOMEM , "ENOMEM"}, + { EEXIST , "EEXIST"}, + { ENOTDIR , "ENOTDIR"}, + { EISDIR , "EISDIR"}, + { ENFILE, "ENFILE"}, + { EROFS, "EROFS"}, + { EFAULT, "EFAULT"}, + { 0, NULL } +}; + +const char *yaffs_error_to_str(int err) +{ + const struct error_entry *e = error_list; + + if (err < 0) + err = -err; + + while (e->code && e->text) { + if (err == e->code) + return e->text; + e++; + } + return "Unknown error code"; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h new file mode 100644 index 0000000..e6e8979 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif.h @@ -0,0 +1,35 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_FLASH_H__ +#define __YAFFS_FLASH_H__ + + +#include "yaffs_guts.h" +int yflash_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber); +int yflash_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk, + const u8 *data, const struct yaffs_spare *spare); +int yflash_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk, + const u8 *data, const struct yaffs_ext_tags *tags); +int yflash_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk, + u8 *data, struct yaffs_spare *spare); +int yflash_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk, + u8 *data, struct yaffs_ext_tags *tags); +int yflash_InitialiseNAND(struct yaffs_dev *dev); +int yflash_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no); +int yflash_QueryNANDBlock(struct yaffs_dev *dev, int block_no, + enum yaffs_block_state *state, u32 *seq_number); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h new file mode 100644 index 0000000..cfdbde9 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_flashif2.h @@ -0,0 +1,35 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_FLASH2_H__ +#define __YAFFS_FLASH2_H__ + + +#include "yaffs_guts.h" +int yflash2_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber); +int yflash2_WriteChunkToNAND(struct yaffs_dev *dev, int nand_chunk, + const u8 *data, const struct yaffs_spare *spare); +int yflash2_WriteChunkWithTagsToNAND(struct yaffs_dev *dev, int nand_chunk, + const u8 *data, const struct yaffs_ext_tags *tags); +int yflash2_ReadChunkFromNAND(struct yaffs_dev *dev, int nand_chunk, + u8 *data, struct yaffs_spare *spare); +int yflash2_ReadChunkWithTagsFromNAND(struct yaffs_dev *dev, int nand_chunk, + u8 *data, struct yaffs_ext_tags *tags); +int yflash2_InitialiseNAND(struct yaffs_dev *dev); +int yflash2_MarkNANDBlockBad(struct yaffs_dev *dev, int block_no); +int yflash2_QueryNANDBlock(struct yaffs_dev *dev, int block_no, + enum yaffs_block_state *state, u32 *seq_number); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h new file mode 100644 index 0000000..8fd0802 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_getblockinfo.h @@ -0,0 +1,35 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_GETBLOCKINFO_H__ +#define __YAFFS_GETBLOCKINFO_H__ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" + +/* Function to manipulate block info */ +static inline struct yaffs_block_info *yaffs_get_block_info(struct yaffs_dev + *dev, int blk) +{ + if (blk < dev->internal_start_block || blk > dev->internal_end_block) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>> yaffs: get_block_info block %d is not valid", + blk); + BUG(); + } + return &dev->block_info[blk - dev->internal_start_block]; +} + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c new file mode 100644 index 0000000..9c296e2 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.c @@ -0,0 +1,5053 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yportenv.h" +#include "yaffs_trace.h" + +#include "yaffs_guts.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_tagscompat.h" +#include "yaffs_nand.h" +#include "yaffs_yaffs1.h" +#include "yaffs_yaffs2.h" +#include "yaffs_bitmap.h" +#include "yaffs_verify.h" +#include "yaffs_nand.h" +#include "yaffs_packedtags2.h" +#include "yaffs_nameval.h" +#include "yaffs_allocator.h" +#include "yaffs_attribs.h" +#include "yaffs_summary.h" + +/* Note YAFFS_GC_GOOD_ENOUGH must be <= YAFFS_GC_PASSIVE_THRESHOLD */ +#define YAFFS_GC_GOOD_ENOUGH 2 +#define YAFFS_GC_PASSIVE_THRESHOLD 4 + +#include "yaffs_ecc.h" + +/* Forward declarations */ + +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, + const u8 *buffer, int n_bytes, int use_reserve); + +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, + int buffer_size); + +/* Function to calculate chunk and offset */ + +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, + int *chunk_out, u32 *offset_out) +{ + int chunk; + u32 offset; + + chunk = (u32) (addr >> dev->chunk_shift); + + if (dev->chunk_div == 1) { + /* easy power of 2 case */ + offset = (u32) (addr & dev->chunk_mask); + } else { + /* Non power-of-2 case */ + + loff_t chunk_base; + + chunk /= dev->chunk_div; + + chunk_base = ((loff_t) chunk) * dev->data_bytes_per_chunk; + offset = (u32) (addr - chunk_base); + } + + *chunk_out = chunk; + *offset_out = offset; +} + +/* Function to return the number of shifts for a power of 2 greater than or + * equal to the given number + * Note we don't try to cater for all possible numbers and this does not have to + * be hellishly efficient. + */ + +static inline u32 calc_shifts_ceiling(u32 x) +{ + int extra_bits; + int shifts; + + shifts = extra_bits = 0; + + while (x > 1) { + if (x & 1) + extra_bits++; + x >>= 1; + shifts++; + } + + if (extra_bits) + shifts++; + + return shifts; +} + +/* Function to return the number of shifts to get a 1 in bit 0 + */ + +static inline u32 calc_shifts(u32 x) +{ + u32 shifts; + + shifts = 0; + + if (!x) + return 0; + + while (!(x & 1)) { + x >>= 1; + shifts++; + } + + return shifts; +} + +/* + * Temporary buffer manipulations. + */ + +static int yaffs_init_tmp_buffers(struct yaffs_dev *dev) +{ + int i; + u8 *buf = (u8 *) 1; + + memset(dev->temp_buffer, 0, sizeof(dev->temp_buffer)); + + for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) { + dev->temp_buffer[i].in_use = 0; + buf = kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); + dev->temp_buffer[i].buffer = buf; + } + + return buf ? YAFFS_OK : YAFFS_FAIL; +} + +u8 *yaffs_get_temp_buffer(struct yaffs_dev * dev) +{ + int i; + + dev->temp_in_use++; + if (dev->temp_in_use > dev->max_temp) + dev->max_temp = dev->temp_in_use; + + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + if (dev->temp_buffer[i].in_use == 0) { + dev->temp_buffer[i].in_use = 1; + return dev->temp_buffer[i].buffer; + } + } + + yaffs_trace(YAFFS_TRACE_BUFFERS, "Out of temp buffers"); + /* + * If we got here then we have to allocate an unmanaged one + * This is not good. + */ + + dev->unmanaged_buffer_allocs++; + return kmalloc(dev->data_bytes_per_chunk, GFP_NOFS); + +} + +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer) +{ + int i; + + dev->temp_in_use--; + + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) { + if (dev->temp_buffer[i].buffer == buffer) { + dev->temp_buffer[i].in_use = 0; + return; + } + } + + if (buffer) { + /* assume it is an unmanaged one. */ + yaffs_trace(YAFFS_TRACE_BUFFERS, + "Releasing unmanaged temp buffer"); + kfree(buffer); + dev->unmanaged_buffer_deallocs++; + } + +} + +/* + * Functions for robustisizing TODO + * + */ + +static void yaffs_handle_chunk_wr_ok(struct yaffs_dev *dev, int nand_chunk, + const u8 *data, + const struct yaffs_ext_tags *tags) +{ + (void) dev; + (void) nand_chunk; + (void) data; + (void) tags; +} + +static void yaffs_handle_chunk_update(struct yaffs_dev *dev, int nand_chunk, + const struct yaffs_ext_tags *tags) +{ + (void) dev; + (void) nand_chunk; + (void) tags; +} + +void yaffs_handle_chunk_error(struct yaffs_dev *dev, + struct yaffs_block_info *bi) +{ + if (!bi->gc_prioritise) { + bi->gc_prioritise = 1; + dev->has_pending_prioritised_gc = 1; + bi->chunk_error_strikes++; + + if (bi->chunk_error_strikes > 3) { + bi->needs_retiring = 1; /* Too many stikes, so retire */ + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Block struck out"); + + } + } +} + +static void yaffs_handle_chunk_wr_error(struct yaffs_dev *dev, int nand_chunk, + int erased_ok) +{ + int flash_block = nand_chunk / dev->param.chunks_per_block; + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); + + yaffs_handle_chunk_error(dev, bi); + + if (erased_ok) { + /* Was an actual write failure, + * so mark the block for retirement.*/ + bi->needs_retiring = 1; + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>> Block %d needs retiring", flash_block); + } + + /* Delete the chunk */ + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); + yaffs_skip_rest_of_block(dev); +} + +/* + * Verification code + */ + +/* + * Simple hash function. Needs to have a reasonable spread + */ + +static inline int yaffs_hash_fn(int n) +{ + if (n < 0) + n = -n; + return n % YAFFS_NOBJECT_BUCKETS; +} + +/* + * Access functions to useful fake objects. + * Note that root might have a presence in NAND if permissions are set. + */ + +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev) +{ + return dev->root_dir; +} + +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev) +{ + return dev->lost_n_found; +} + +/* + * Erased NAND checking functions + */ + +int yaffs_check_ff(u8 *buffer, int n_bytes) +{ + /* Horrible, slow implementation */ + while (n_bytes--) { + if (*buffer != 0xff) + return 0; + buffer++; + } + return 1; +} + +static int yaffs_check_chunk_erased(struct yaffs_dev *dev, int nand_chunk) +{ + int retval = YAFFS_OK; + u8 *data = yaffs_get_temp_buffer(dev); + struct yaffs_ext_tags tags; + int result; + + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, data, &tags); + + if (tags.ecc_result > YAFFS_ECC_RESULT_NO_ERROR) + retval = YAFFS_FAIL; + + if (!yaffs_check_ff(data, dev->data_bytes_per_chunk) || + tags.chunk_used) { + yaffs_trace(YAFFS_TRACE_NANDACCESS, + "Chunk %d not erased", nand_chunk); + retval = YAFFS_FAIL; + } + + yaffs_release_temp_buffer(dev, data); + + return retval; + +} + +static int yaffs_verify_chunk_written(struct yaffs_dev *dev, + int nand_chunk, + const u8 *data, + struct yaffs_ext_tags *tags) +{ + int retval = YAFFS_OK; + struct yaffs_ext_tags temp_tags; + u8 *buffer = yaffs_get_temp_buffer(dev); + int result; + + result = yaffs_rd_chunk_tags_nand(dev, nand_chunk, buffer, &temp_tags); + if (memcmp(buffer, data, dev->data_bytes_per_chunk) || + temp_tags.obj_id != tags->obj_id || + temp_tags.chunk_id != tags->chunk_id || + temp_tags.n_bytes != tags->n_bytes) + retval = YAFFS_FAIL; + + yaffs_release_temp_buffer(dev, buffer); + + return retval; +} + + +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks) +{ + int reserved_chunks; + int reserved_blocks = dev->param.n_reserved_blocks; + int checkpt_blocks; + + checkpt_blocks = yaffs_calc_checkpt_blocks_required(dev); + + reserved_chunks = + (reserved_blocks + checkpt_blocks) * dev->param.chunks_per_block; + + return (dev->n_free_chunks > (reserved_chunks + n_chunks)); +} + +static int yaffs_find_alloc_block(struct yaffs_dev *dev) +{ + int i; + struct yaffs_block_info *bi; + + if (dev->n_erased_blocks < 1) { + /* Hoosterman we've got a problem. + * Can't get space to gc + */ + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: no more erased blocks"); + + return -1; + } + + /* Find an empty block. */ + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + dev->alloc_block_finder++; + if (dev->alloc_block_finder < dev->internal_start_block + || dev->alloc_block_finder > dev->internal_end_block) { + dev->alloc_block_finder = dev->internal_start_block; + } + + bi = yaffs_get_block_info(dev, dev->alloc_block_finder); + + if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { + bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->seq_number++; + bi->seq_number = dev->seq_number; + dev->n_erased_blocks--; + yaffs_trace(YAFFS_TRACE_ALLOCATE, + "Allocated block %d, seq %d, %d left" , + dev->alloc_block_finder, dev->seq_number, + dev->n_erased_blocks); + return dev->alloc_block_finder; + } + } + + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs tragedy: no more erased blocks, but there should have been %d", + dev->n_erased_blocks); + + return -1; +} + +static int yaffs_alloc_chunk(struct yaffs_dev *dev, int use_reserver, + struct yaffs_block_info **block_ptr) +{ + int ret_val; + struct yaffs_block_info *bi; + + if (dev->alloc_block < 0) { + /* Get next block to allocate off */ + dev->alloc_block = yaffs_find_alloc_block(dev); + dev->alloc_page = 0; + } + + if (!use_reserver && !yaffs_check_alloc_available(dev, 1)) { + /* No space unless we're allowed to use the reserve. */ + return -1; + } + + if (dev->n_erased_blocks < dev->param.n_reserved_blocks + && dev->alloc_page == 0) + yaffs_trace(YAFFS_TRACE_ALLOCATE, "Allocating reserve"); + + /* Next page please.... */ + if (dev->alloc_block >= 0) { + bi = yaffs_get_block_info(dev, dev->alloc_block); + + ret_val = (dev->alloc_block * dev->param.chunks_per_block) + + dev->alloc_page; + bi->pages_in_use++; + yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page); + + dev->alloc_page++; + + dev->n_free_chunks--; + + /* If the block is full set the state to full */ + if (dev->alloc_page >= dev->param.chunks_per_block) { + bi->block_state = YAFFS_BLOCK_STATE_FULL; + dev->alloc_block = -1; + } + + if (block_ptr) + *block_ptr = bi; + + return ret_val; + } + + yaffs_trace(YAFFS_TRACE_ERROR, + "!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!"); + + return -1; +} + +static int yaffs_get_erased_chunks(struct yaffs_dev *dev) +{ + int n; + + n = dev->n_erased_blocks * dev->param.chunks_per_block; + + if (dev->alloc_block > 0) + n += (dev->param.chunks_per_block - dev->alloc_page); + + return n; + +} + +/* + * yaffs_skip_rest_of_block() skips over the rest of the allocation block + * if we don't want to write to it. + */ +void yaffs_skip_rest_of_block(struct yaffs_dev *dev) +{ + struct yaffs_block_info *bi; + + if (dev->alloc_block > 0) { + bi = yaffs_get_block_info(dev, dev->alloc_block); + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { + bi->block_state = YAFFS_BLOCK_STATE_FULL; + dev->alloc_block = -1; + } + } +} + +static int yaffs_write_new_chunk(struct yaffs_dev *dev, + const u8 *data, + struct yaffs_ext_tags *tags, int use_reserver) +{ + int attempts = 0; + int write_ok = 0; + int chunk; + + yaffs2_checkpt_invalidate(dev); + + do { + struct yaffs_block_info *bi = 0; + int erased_ok = 0; + + chunk = yaffs_alloc_chunk(dev, use_reserver, &bi); + if (chunk < 0) { + /* no space */ + break; + } + + /* First check this chunk is erased, if it needs + * checking. The checking policy (unless forced + * always on) is as follows: + * + * Check the first page we try to write in a block. + * If the check passes then we don't need to check any + * more. If the check fails, we check again... + * If the block has been erased, we don't need to check. + * + * However, if the block has been prioritised for gc, + * then we think there might be something odd about + * this block and stop using it. + * + * Rationale: We should only ever see chunks that have + * not been erased if there was a partially written + * chunk due to power loss. This checking policy should + * catch that case with very few checks and thus save a + * lot of checks that are most likely not needed. + * + * Mods to the above + * If an erase check fails or the write fails we skip the + * rest of the block. + */ + + /* let's give it a try */ + attempts++; + + if (dev->param.always_check_erased) + bi->skip_erased_check = 0; + + if (!bi->skip_erased_check) { + erased_ok = yaffs_check_chunk_erased(dev, chunk); + if (erased_ok != YAFFS_OK) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>> yaffs chunk %d was not erased", + chunk); + + /* If not erased, delete this one, + * skip rest of block and + * try another chunk */ + yaffs_chunk_del(dev, chunk, 1, __LINE__); + yaffs_skip_rest_of_block(dev); + continue; + } + } + + write_ok = yaffs_wr_chunk_tags_nand(dev, chunk, data, tags); + + if (!bi->skip_erased_check) + write_ok = + yaffs_verify_chunk_written(dev, chunk, data, tags); + + if (write_ok != YAFFS_OK) { + /* Clean up aborted write, skip to next block and + * try another chunk */ + yaffs_handle_chunk_wr_error(dev, chunk, erased_ok); + continue; + } + + bi->skip_erased_check = 1; + + /* Copy the data into the robustification buffer */ + yaffs_handle_chunk_wr_ok(dev, chunk, data, tags); + + } while (write_ok != YAFFS_OK && + (yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts)); + + if (!write_ok) + chunk = -1; + + if (attempts > 1) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>> yaffs write required %d attempts", + attempts); + dev->n_retried_writes += (attempts - 1); + } + + return chunk; +} + +/* + * Block retiring for handling a broken block. + */ + +static void yaffs_retire_block(struct yaffs_dev *dev, int flash_block) +{ + struct yaffs_block_info *bi = yaffs_get_block_info(dev, flash_block); + + yaffs2_checkpt_invalidate(dev); + + yaffs2_clear_oldest_dirty_seq(dev, bi); + + if (yaffs_mark_bad(dev, flash_block) != YAFFS_OK) { + if (yaffs_erase_block(dev, flash_block) != YAFFS_OK) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Failed to mark bad and erase block %d", + flash_block); + } else { + struct yaffs_ext_tags tags; + int chunk_id = + flash_block * dev->param.chunks_per_block; + + u8 *buffer = yaffs_get_temp_buffer(dev); + + memset(buffer, 0xff, dev->data_bytes_per_chunk); + memset(&tags, 0, sizeof(tags)); + tags.seq_number = YAFFS_SEQUENCE_BAD_BLOCK; + if (dev->param.write_chunk_tags_fn(dev, chunk_id - + dev->chunk_offset, + buffer, + &tags) != YAFFS_OK) + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Failed to write bad block marker to block %d", + flash_block); + + yaffs_release_temp_buffer(dev, buffer); + } + } + + bi->block_state = YAFFS_BLOCK_STATE_DEAD; + bi->gc_prioritise = 0; + bi->needs_retiring = 0; + + dev->n_retired_blocks++; +} + +/*---------------- Name handling functions ------------*/ + +static u16 yaffs_calc_name_sum(const YCHAR *name) +{ + u16 sum = 0; + u16 i = 1; + + if (!name) + return 0; + + while ((*name) && i < (YAFFS_MAX_NAME_LENGTH / 2)) { + + /* 0x1f mask is case insensitive */ + sum += ((*name) & 0x1f) * i; + i++; + name++; + } + return sum; +} + + +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR * name) +{ + memset(obj->short_name, 0, sizeof(obj->short_name)); + + if (name && !name[0]) { + yaffs_fix_null_name(obj, obj->short_name, + YAFFS_SHORT_NAME_LENGTH); + name = obj->short_name; + } else if (name && + strnlen(name, YAFFS_SHORT_NAME_LENGTH + 1) <= + YAFFS_SHORT_NAME_LENGTH) { + strcpy(obj->short_name, name); + } + + obj->sum = yaffs_calc_name_sum(name); +} + +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, + const struct yaffs_obj_hdr *oh) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + YCHAR tmp_name[YAFFS_MAX_NAME_LENGTH + 1]; + memset(tmp_name, 0, sizeof(tmp_name)); + yaffs_load_name_from_oh(obj->my_dev, tmp_name, oh->name, + YAFFS_MAX_NAME_LENGTH + 1); + yaffs_set_obj_name(obj, tmp_name); +#else + yaffs_set_obj_name(obj, oh->name); +#endif +} + +loff_t yaffs_max_file_size(struct yaffs_dev *dev) +{ + if(sizeof(loff_t) < 8) + return YAFFS_MAX_FILE_SIZE_32; + else + return ((loff_t) YAFFS_MAX_CHUNK_ID) * dev->data_bytes_per_chunk; +} + +/*-------------------- TNODES ------------------- + + * List of spare tnodes + * The list is hooked together using the first pointer + * in the tnode. + */ + +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev) +{ + struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev); + + if (tn) { + memset(tn, 0, dev->tnode_size); + dev->n_tnodes++; + } + + dev->checkpoint_blocks_required = 0; /* force recalculation */ + + return tn; +} + +/* FreeTnode frees up a tnode and puts it back on the free list */ +static void yaffs_free_tnode(struct yaffs_dev *dev, struct yaffs_tnode *tn) +{ + yaffs_free_raw_tnode(dev, tn); + dev->n_tnodes--; + dev->checkpoint_blocks_required = 0; /* force recalculation */ +} + +static void yaffs_deinit_tnodes_and_objs(struct yaffs_dev *dev) +{ + yaffs_deinit_raw_tnodes_and_objs(dev); + dev->n_obj = 0; + dev->n_tnodes = 0; +} + +static void yaffs_load_tnode_0(struct yaffs_dev *dev, struct yaffs_tnode *tn, + unsigned pos, unsigned val) +{ + u32 *map = (u32 *) tn; + u32 bit_in_map; + u32 bit_in_word; + u32 word_in_map; + u32 mask; + + pos &= YAFFS_TNODES_LEVEL0_MASK; + val >>= dev->chunk_grp_bits; + + bit_in_map = pos * dev->tnode_width; + word_in_map = bit_in_map / 32; + bit_in_word = bit_in_map & (32 - 1); + + mask = dev->tnode_mask << bit_in_word; + + map[word_in_map] &= ~mask; + map[word_in_map] |= (mask & (val << bit_in_word)); + + if (dev->tnode_width > (32 - bit_in_word)) { + bit_in_word = (32 - bit_in_word); + word_in_map++; + mask = + dev->tnode_mask >> bit_in_word; + map[word_in_map] &= ~mask; + map[word_in_map] |= (mask & (val >> bit_in_word)); + } +} + +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, + unsigned pos) +{ + u32 *map = (u32 *) tn; + u32 bit_in_map; + u32 bit_in_word; + u32 word_in_map; + u32 val; + + pos &= YAFFS_TNODES_LEVEL0_MASK; + + bit_in_map = pos * dev->tnode_width; + word_in_map = bit_in_map / 32; + bit_in_word = bit_in_map & (32 - 1); + + val = map[word_in_map] >> bit_in_word; + + if (dev->tnode_width > (32 - bit_in_word)) { + bit_in_word = (32 - bit_in_word); + word_in_map++; + val |= (map[word_in_map] << bit_in_word); + } + + val &= dev->tnode_mask; + val <<= dev->chunk_grp_bits; + + return val; +} + +/* ------------------- End of individual tnode manipulation -----------------*/ + +/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------ + * The look up tree is represented by the top tnode and the number of top_level + * in the tree. 0 means only the level 0 tnode is in the tree. + */ + +/* FindLevel0Tnode finds the level 0 tnode, if one exists. */ +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id) +{ + struct yaffs_tnode *tn = file_struct->top; + u32 i; + int required_depth; + int level = file_struct->top_level; + + (void) dev; + + /* Check sane level and chunk Id */ + if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL) + return NULL; + + if (chunk_id > YAFFS_MAX_CHUNK_ID) + return NULL; + + /* First check we're tall enough (ie enough top_level) */ + + i = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; + required_depth = 0; + while (i) { + i >>= YAFFS_TNODES_INTERNAL_BITS; + required_depth++; + } + + if (required_depth > file_struct->top_level) + return NULL; /* Not tall enough, so we can't find it */ + + /* Traverse down to level 0 */ + while (level > 0 && tn) { + tn = tn->internal[(chunk_id >> + (YAFFS_TNODES_LEVEL0_BITS + + (level - 1) * + YAFFS_TNODES_INTERNAL_BITS)) & + YAFFS_TNODES_INTERNAL_MASK]; + level--; + } + + return tn; +} + +/* add_find_tnode_0 finds the level 0 tnode if it exists, + * otherwise first expands the tree. + * This happens in two steps: + * 1. If the tree isn't tall enough, then make it taller. + * 2. Scan down the tree towards the level 0 tnode adding tnodes if required. + * + * Used when modifying the tree. + * + * If the tn argument is NULL, then a fresh tnode will be added otherwise the + * specified tn will be plugged into the ttree. + */ + +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id, + struct yaffs_tnode *passed_tn) +{ + int required_depth; + int i; + int l; + struct yaffs_tnode *tn; + u32 x; + + /* Check sane level and page Id */ + if (file_struct->top_level < 0 || + file_struct->top_level > YAFFS_TNODES_MAX_LEVEL) + return NULL; + + if (chunk_id > YAFFS_MAX_CHUNK_ID) + return NULL; + + /* First check we're tall enough (ie enough top_level) */ + + x = chunk_id >> YAFFS_TNODES_LEVEL0_BITS; + required_depth = 0; + while (x) { + x >>= YAFFS_TNODES_INTERNAL_BITS; + required_depth++; + } + + if (required_depth > file_struct->top_level) { + /* Not tall enough, gotta make the tree taller */ + for (i = file_struct->top_level; i < required_depth; i++) { + + tn = yaffs_get_tnode(dev); + + if (tn) { + tn->internal[0] = file_struct->top; + file_struct->top = tn; + file_struct->top_level++; + } else { + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs: no more tnodes"); + return NULL; + } + } + } + + /* Traverse down to level 0, adding anything we need */ + + l = file_struct->top_level; + tn = file_struct->top; + + if (l > 0) { + while (l > 0 && tn) { + x = (chunk_id >> + (YAFFS_TNODES_LEVEL0_BITS + + (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) & + YAFFS_TNODES_INTERNAL_MASK; + + if ((l > 1) && !tn->internal[x]) { + /* Add missing non-level-zero tnode */ + tn->internal[x] = yaffs_get_tnode(dev); + if (!tn->internal[x]) + return NULL; + } else if (l == 1) { + /* Looking from level 1 at level 0 */ + if (passed_tn) { + /* If we already have one, release it */ + if (tn->internal[x]) + yaffs_free_tnode(dev, + tn->internal[x]); + tn->internal[x] = passed_tn; + + } else if (!tn->internal[x]) { + /* Don't have one, none passed in */ + tn->internal[x] = yaffs_get_tnode(dev); + if (!tn->internal[x]) + return NULL; + } + } + + tn = tn->internal[x]; + l--; + } + } else { + /* top is level 0 */ + if (passed_tn) { + memcpy(tn, passed_tn, + (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8); + yaffs_free_tnode(dev, passed_tn); + } + } + + return tn; +} + +static int yaffs_tags_match(const struct yaffs_ext_tags *tags, int obj_id, + int chunk_obj) +{ + return (tags->chunk_id == chunk_obj && + tags->obj_id == obj_id && + !tags->is_deleted) ? 1 : 0; + +} + +static int yaffs_find_chunk_in_group(struct yaffs_dev *dev, int the_chunk, + struct yaffs_ext_tags *tags, int obj_id, + int inode_chunk) +{ + int j; + + for (j = 0; the_chunk && j < dev->chunk_grp_size; j++) { + if (yaffs_check_chunk_bit + (dev, the_chunk / dev->param.chunks_per_block, + the_chunk % dev->param.chunks_per_block)) { + + if (dev->chunk_grp_size == 1) + return the_chunk; + else { + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, + tags); + if (yaffs_tags_match(tags, + obj_id, inode_chunk)) { + /* found it; */ + return the_chunk; + } + } + } + the_chunk++; + } + return -1; +} + +static int yaffs_find_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + struct yaffs_ext_tags *tags) +{ + /*Get the Tnode, then get the level 0 offset chunk offset */ + struct yaffs_tnode *tn; + int the_chunk = -1; + struct yaffs_ext_tags local_tags; + int ret_val = -1; + struct yaffs_dev *dev = in->my_dev; + + if (!tags) { + /* Passed a NULL, so use our own tags space */ + tags = &local_tags; + } + + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); + + if (!tn) + return ret_val; + + the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); + + ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, + inode_chunk); + return ret_val; +} + +static int yaffs_find_del_file_chunk(struct yaffs_obj *in, int inode_chunk, + struct yaffs_ext_tags *tags) +{ + /* Get the Tnode, then get the level 0 offset chunk offset */ + struct yaffs_tnode *tn; + int the_chunk = -1; + struct yaffs_ext_tags local_tags; + struct yaffs_dev *dev = in->my_dev; + int ret_val = -1; + + if (!tags) { + /* Passed a NULL, so use our own tags space */ + tags = &local_tags; + } + + tn = yaffs_find_tnode_0(dev, &in->variant.file_variant, inode_chunk); + + if (!tn) + return ret_val; + + the_chunk = yaffs_get_group_base(dev, tn, inode_chunk); + + ret_val = yaffs_find_chunk_in_group(dev, the_chunk, tags, in->obj_id, + inode_chunk); + + /* Delete the entry in the filestructure (if found) */ + if (ret_val != -1) + yaffs_load_tnode_0(dev, tn, inode_chunk, 0); + + return ret_val; +} + +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + int nand_chunk, int in_scan) +{ + /* NB in_scan is zero unless scanning. + * For forward scanning, in_scan is > 0; + * for backward scanning in_scan is < 0 + * + * nand_chunk = 0 is a dummy insert to make sure the tnodes are there. + */ + + struct yaffs_tnode *tn; + struct yaffs_dev *dev = in->my_dev; + int existing_cunk; + struct yaffs_ext_tags existing_tags; + struct yaffs_ext_tags new_tags; + unsigned existing_serial, new_serial; + + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) { + /* Just ignore an attempt at putting a chunk into a non-file + * during scanning. + * If it is not during Scanning then something went wrong! + */ + if (!in_scan) { + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy:attempt to put data chunk into a non-file" + ); + BUG(); + } + + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); + return YAFFS_OK; + } + + tn = yaffs_add_find_tnode_0(dev, + &in->variant.file_variant, + inode_chunk, NULL); + if (!tn) + return YAFFS_FAIL; + + if (!nand_chunk) + /* Dummy insert, bail now */ + return YAFFS_OK; + + existing_cunk = yaffs_get_group_base(dev, tn, inode_chunk); + + if (in_scan != 0) { + /* If we're scanning then we need to test for duplicates + * NB This does not need to be efficient since it should only + * happen when the power fails during a write, then only one + * chunk should ever be affected. + * + * Correction for YAFFS2: This could happen quite a lot and we + * need to think about efficiency! TODO + * Update: For backward scanning we don't need to re-read tags + * so this is quite cheap. + */ + + if (existing_cunk > 0) { + /* NB Right now existing chunk will not be real + * chunk_id if the chunk group size > 1 + * thus we have to do a FindChunkInFile to get the + * real chunk id. + * + * We have a duplicate now we need to decide which + * one to use: + * + * Backwards scanning YAFFS2: The old one is what + * we use, dump the new one. + * YAFFS1: Get both sets of tags and compare serial + * numbers. + */ + + if (in_scan > 0) { + /* Only do this for forward scanning */ + yaffs_rd_chunk_tags_nand(dev, + nand_chunk, + NULL, &new_tags); + + /* Do a proper find */ + existing_cunk = + yaffs_find_chunk_in_file(in, inode_chunk, + &existing_tags); + } + + if (existing_cunk <= 0) { + /*Hoosterman - how did this happen? */ + + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: existing chunk < 0 in scan" + ); + + } + + /* NB The deleted flags should be false, otherwise + * the chunks will not be loaded during a scan + */ + + if (in_scan > 0) { + new_serial = new_tags.serial_number; + existing_serial = existing_tags.serial_number; + } + + if ((in_scan > 0) && + (existing_cunk <= 0 || + ((existing_serial + 1) & 3) == new_serial)) { + /* Forward scanning. + * Use new + * Delete the old one and drop through to + * update the tnode + */ + yaffs_chunk_del(dev, existing_cunk, 1, + __LINE__); + } else { + /* Backward scanning or we want to use the + * existing one + * Delete the new one and return early so that + * the tnode isn't changed + */ + yaffs_chunk_del(dev, nand_chunk, 1, __LINE__); + return YAFFS_OK; + } + } + + } + + if (existing_cunk == 0) + in->n_data_chunks++; + + yaffs_load_tnode_0(dev, tn, inode_chunk, nand_chunk); + + return YAFFS_OK; +} + +static void yaffs_soft_del_chunk(struct yaffs_dev *dev, int chunk) +{ + struct yaffs_block_info *the_block; + unsigned block_no; + + yaffs_trace(YAFFS_TRACE_DELETION, "soft delete chunk %d", chunk); + + block_no = chunk / dev->param.chunks_per_block; + the_block = yaffs_get_block_info(dev, block_no); + if (the_block) { + the_block->soft_del_pages++; + dev->n_free_chunks++; + yaffs2_update_oldest_dirty_seq(dev, block_no, the_block); + } +} + +/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all + * the chunks in the file. + * All soft deleting does is increment the block's softdelete count and pulls + * the chunk out of the tnode. + * Thus, essentially this is the same as DeleteWorker except that the chunks + * are soft deleted. + */ + +static int yaffs_soft_del_worker(struct yaffs_obj *in, struct yaffs_tnode *tn, + u32 level, int chunk_offset) +{ + int i; + int the_chunk; + int all_done = 1; + struct yaffs_dev *dev = in->my_dev; + + if (!tn) + return 1; + + if (level > 0) { + for (i = YAFFS_NTNODES_INTERNAL - 1; + all_done && i >= 0; + i--) { + if (tn->internal[i]) { + all_done = + yaffs_soft_del_worker(in, + tn->internal[i], + level - 1, + (chunk_offset << + YAFFS_TNODES_INTERNAL_BITS) + + i); + if (all_done) { + yaffs_free_tnode(dev, + tn->internal[i]); + tn->internal[i] = NULL; + } else { + /* Can this happen? */ + } + } + } + return (all_done) ? 1 : 0; + } + + /* level 0 */ + for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) { + the_chunk = yaffs_get_group_base(dev, tn, i); + if (the_chunk) { + yaffs_soft_del_chunk(dev, the_chunk); + yaffs_load_tnode_0(dev, tn, i, 0); + } + } + return 1; +} + +static void yaffs_remove_obj_from_dir(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev = obj->my_dev; + struct yaffs_obj *parent; + + yaffs_verify_obj_in_dir(obj); + parent = obj->parent; + + yaffs_verify_dir(parent); + + if (dev && dev->param.remove_obj_fn) + dev->param.remove_obj_fn(obj); + + list_del_init(&obj->siblings); + obj->parent = NULL; + + yaffs_verify_dir(parent); +} + +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj) +{ + if (!directory) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: Trying to add an object to a null pointer directory" + ); + BUG(); + return; + } + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: Trying to add an object to a non-directory" + ); + BUG(); + } + + if (obj->siblings.prev == NULL) { + /* Not initialised */ + BUG(); + } + + yaffs_verify_dir(directory); + + yaffs_remove_obj_from_dir(obj); + + /* Now add it */ + list_add(&obj->siblings, &directory->variant.dir_variant.children); + obj->parent = directory; + + if (directory == obj->my_dev->unlinked_dir + || directory == obj->my_dev->del_dir) { + obj->unlinked = 1; + obj->my_dev->n_unlinked_files++; + obj->rename_allowed = 0; + } + + yaffs_verify_dir(directory); + yaffs_verify_obj_in_dir(obj); +} + +static int yaffs_change_obj_name(struct yaffs_obj *obj, + struct yaffs_obj *new_dir, + const YCHAR *new_name, int force, int shadows) +{ + int unlink_op; + int del_op; + struct yaffs_obj *existing_target; + + if (new_dir == NULL) + new_dir = obj->parent; /* use the old directory */ + + if (new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: yaffs_change_obj_name: new_dir is not a directory" + ); + BUG(); + } + + unlink_op = (new_dir == obj->my_dev->unlinked_dir); + del_op = (new_dir == obj->my_dev->del_dir); + + existing_target = yaffs_find_by_name(new_dir, new_name); + + /* If the object is a file going into the unlinked directory, + * then it is OK to just stuff it in since duplicate names are OK. + * else only proceed if the new name does not exist and we're putting + * it into a directory. + */ + if (!(unlink_op || del_op || force || + shadows > 0 || !existing_target) || + new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + return YAFFS_FAIL; + + yaffs_set_obj_name(obj, new_name); + obj->dirty = 1; + yaffs_add_obj_to_dir(new_dir, obj); + + if (unlink_op) + obj->unlinked = 1; + + /* If it is a deletion then we mark it as a shrink for gc */ + if (yaffs_update_oh(obj, new_name, 0, del_op, shadows, NULL) >= 0) + return YAFFS_OK; + + return YAFFS_FAIL; +} + +/*------------------------ Short Operations Cache ------------------------------ + * In many situations where there is no high level buffering a lot of + * reads might be short sequential reads, and a lot of writes may be short + * sequential writes. eg. scanning/writing a jpeg file. + * In these cases, a short read/write cache can provide a huge perfomance + * benefit with dumb-as-a-rock code. + * In Linux, the page cache provides read buffering and the short op cache + * provides write buffering. + * + * There are a small number (~10) of cache chunks per device so that we don't + * need a very intelligent search. + */ + +static int yaffs_obj_cache_dirty(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev = obj->my_dev; + int i; + struct yaffs_cache *cache; + int n_caches = obj->my_dev->param.n_caches; + + for (i = 0; i < n_caches; i++) { + cache = &dev->cache[i]; + if (cache->object == obj && cache->dirty) + return 1; + } + + return 0; +} + +static void yaffs_flush_file_cache(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev = obj->my_dev; + int lowest = -99; /* Stop compiler whining. */ + int i; + struct yaffs_cache *cache; + int chunk_written = 0; + int n_caches = obj->my_dev->param.n_caches; + + if (n_caches < 1) + return; + do { + cache = NULL; + + /* Find the lowest dirty chunk for this object */ + for (i = 0; i < n_caches; i++) { + if (dev->cache[i].object == obj && + dev->cache[i].dirty) { + if (!cache || + dev->cache[i].chunk_id < lowest) { + cache = &dev->cache[i]; + lowest = cache->chunk_id; + } + } + } + + if (cache && !cache->locked) { + /* Write it out and free it up */ + chunk_written = + yaffs_wr_data_obj(cache->object, + cache->chunk_id, + cache->data, + cache->n_bytes, 1); + cache->dirty = 0; + cache->object = NULL; + } + } while (cache && chunk_written > 0); + + if (cache) + /* Hoosterman, disk full while writing cache out. */ + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: no space during cache write"); +} + +/*yaffs_flush_whole_cache(dev) + * + * + */ + +void yaffs_flush_whole_cache(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + int n_caches = dev->param.n_caches; + int i; + + /* Find a dirty object in the cache and flush it... + * until there are no further dirty objects. + */ + do { + obj = NULL; + for (i = 0; i < n_caches && !obj; i++) { + if (dev->cache[i].object && dev->cache[i].dirty) + obj = dev->cache[i].object; + } + if (obj) + yaffs_flush_file_cache(obj); + } while (obj); + +} + +/* Grab us a cache chunk for use. + * First look for an empty one. + * Then look for the least recently used non-dirty one. + * Then look for the least recently used dirty one...., flush and look again. + */ +static struct yaffs_cache *yaffs_grab_chunk_worker(struct yaffs_dev *dev) +{ + int i; + + if (dev->param.n_caches > 0) { + for (i = 0; i < dev->param.n_caches; i++) { + if (!dev->cache[i].object) + return &dev->cache[i]; + } + } + return NULL; +} + +static struct yaffs_cache *yaffs_grab_chunk_cache(struct yaffs_dev *dev) +{ + struct yaffs_cache *cache; + struct yaffs_obj *the_obj; + int usage; + int i; + int pushout; + + if (dev->param.n_caches < 1) + return NULL; + + /* Try find a non-dirty one... */ + + cache = yaffs_grab_chunk_worker(dev); + + if (!cache) { + /* They were all dirty, find the LRU object and flush + * its cache, then find again. + * NB what's here is not very accurate, + * we actually flush the object with the LRU chunk. + */ + + /* With locking we can't assume we can use entry zero, + * Set the_obj to a valid pointer for Coverity. */ + the_obj = dev->cache[0].object; + usage = -1; + cache = NULL; + pushout = -1; + + for (i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].object && + !dev->cache[i].locked && + (dev->cache[i].last_use < usage || + !cache)) { + usage = dev->cache[i].last_use; + the_obj = dev->cache[i].object; + cache = &dev->cache[i]; + pushout = i; + } + } + + if (!cache || cache->dirty) { + /* Flush and try again */ + yaffs_flush_file_cache(the_obj); + cache = yaffs_grab_chunk_worker(dev); + } + } + return cache; +} + +/* Find a cached chunk */ +static struct yaffs_cache *yaffs_find_chunk_cache(const struct yaffs_obj *obj, + int chunk_id) +{ + struct yaffs_dev *dev = obj->my_dev; + int i; + + if (dev->param.n_caches < 1) + return NULL; + + for (i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].object == obj && + dev->cache[i].chunk_id == chunk_id) { + dev->cache_hits++; + + return &dev->cache[i]; + } + } + return NULL; +} + +/* Mark the chunk for the least recently used algorithym */ +static void yaffs_use_cache(struct yaffs_dev *dev, struct yaffs_cache *cache, + int is_write) +{ + int i; + + if (dev->param.n_caches < 1) + return; + + if (dev->cache_last_use < 0 || + dev->cache_last_use > 100000000) { + /* Reset the cache usages */ + for (i = 1; i < dev->param.n_caches; i++) + dev->cache[i].last_use = 0; + + dev->cache_last_use = 0; + } + dev->cache_last_use++; + cache->last_use = dev->cache_last_use; + + if (is_write) + cache->dirty = 1; +} + +/* Invalidate a single cache page. + * Do this when a whole page gets written, + * ie the short cache for this page is no longer valid. + */ +static void yaffs_invalidate_chunk_cache(struct yaffs_obj *object, int chunk_id) +{ + struct yaffs_cache *cache; + + if (object->my_dev->param.n_caches > 0) { + cache = yaffs_find_chunk_cache(object, chunk_id); + + if (cache) + cache->object = NULL; + } +} + +/* Invalidate all the cache pages associated with this object + * Do this whenever ther file is deleted or resized. + */ +static void yaffs_invalidate_whole_cache(struct yaffs_obj *in) +{ + int i; + struct yaffs_dev *dev = in->my_dev; + + if (dev->param.n_caches > 0) { + /* Invalidate it. */ + for (i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].object == in) + dev->cache[i].object = NULL; + } + } +} + +static void yaffs_unhash_obj(struct yaffs_obj *obj) +{ + int bucket; + struct yaffs_dev *dev = obj->my_dev; + + /* If it is still linked into the bucket list, free from the list */ + if (!list_empty(&obj->hash_link)) { + list_del_init(&obj->hash_link); + bucket = yaffs_hash_fn(obj->obj_id); + dev->obj_bucket[bucket].count--; + } +} + +/* FreeObject frees up a Object and puts it back on the free list */ +static void yaffs_free_obj(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev; + + if (!obj) { + BUG(); + return; + } + dev = obj->my_dev; + yaffs_trace(YAFFS_TRACE_OS, "FreeObject %p inode %p", + obj, obj->my_inode); + if (obj->parent) + BUG(); + if (!list_empty(&obj->siblings)) + BUG(); + + if (obj->my_inode) { + /* We're still hooked up to a cached inode. + * Don't delete now, but mark for later deletion + */ + obj->defered_free = 1; + return; + } + + yaffs_unhash_obj(obj); + + yaffs_free_raw_obj(dev, obj); + dev->n_obj--; + dev->checkpoint_blocks_required = 0; /* force recalculation */ +} + +void yaffs_handle_defered_free(struct yaffs_obj *obj) +{ + if (obj->defered_free) + yaffs_free_obj(obj); +} + +static int yaffs_generic_obj_del(struct yaffs_obj *in) +{ + /* Iinvalidate the file's data in the cache, without flushing. */ + yaffs_invalidate_whole_cache(in); + + if (in->my_dev->param.is_yaffs2 && in->parent != in->my_dev->del_dir) { + /* Move to unlinked directory so we have a deletion record */ + yaffs_change_obj_name(in, in->my_dev->del_dir, _Y("deleted"), 0, + 0); + } + + yaffs_remove_obj_from_dir(in); + yaffs_chunk_del(in->my_dev, in->hdr_chunk, 1, __LINE__); + in->hdr_chunk = 0; + + yaffs_free_obj(in); + return YAFFS_OK; + +} + +static void yaffs_soft_del_file(struct yaffs_obj *obj) +{ + if (!obj->deleted || + obj->variant_type != YAFFS_OBJECT_TYPE_FILE || + obj->soft_del) + return; + + if (obj->n_data_chunks <= 0) { + /* Empty file with no duplicate object headers, + * just delete it immediately */ + yaffs_free_tnode(obj->my_dev, obj->variant.file_variant.top); + obj->variant.file_variant.top = NULL; + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: Deleting empty file %d", + obj->obj_id); + yaffs_generic_obj_del(obj); + } else { + yaffs_soft_del_worker(obj, + obj->variant.file_variant.top, + obj->variant. + file_variant.top_level, 0); + obj->soft_del = 1; + } +} + +/* Pruning removes any part of the file structure tree that is beyond the + * bounds of the file (ie that does not point to chunks). + * + * A file should only get pruned when its size is reduced. + * + * Before pruning, the chunks must be pulled from the tree and the + * level 0 tnode entries must be zeroed out. + * Could also use this for file deletion, but that's probably better handled + * by a special case. + * + * This function is recursive. For levels > 0 the function is called again on + * any sub-tree. For level == 0 we just check if the sub-tree has data. + * If there is no data in a subtree then it is pruned. + */ + +static struct yaffs_tnode *yaffs_prune_worker(struct yaffs_dev *dev, + struct yaffs_tnode *tn, u32 level, + int del0) +{ + int i; + int has_data; + + if (!tn) + return tn; + + has_data = 0; + + if (level > 0) { + for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) { + if (tn->internal[i]) { + tn->internal[i] = + yaffs_prune_worker(dev, + tn->internal[i], + level - 1, + (i == 0) ? del0 : 1); + } + + if (tn->internal[i]) + has_data++; + } + } else { + int tnode_size_u32 = dev->tnode_size / sizeof(u32); + u32 *map = (u32 *) tn; + + for (i = 0; !has_data && i < tnode_size_u32; i++) { + if (map[i]) + has_data++; + } + } + + if (has_data == 0 && del0) { + /* Free and return NULL */ + yaffs_free_tnode(dev, tn); + tn = NULL; + } + return tn; +} + +static int yaffs_prune_tree(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct) +{ + int i; + int has_data; + int done = 0; + struct yaffs_tnode *tn; + + if (file_struct->top_level < 1) + return YAFFS_OK; + + file_struct->top = + yaffs_prune_worker(dev, file_struct->top, file_struct->top_level, 0); + + /* Now we have a tree with all the non-zero branches NULL but + * the height is the same as it was. + * Let's see if we can trim internal tnodes to shorten the tree. + * We can do this if only the 0th element in the tnode is in use + * (ie all the non-zero are NULL) + */ + + while (file_struct->top_level && !done) { + tn = file_struct->top; + + has_data = 0; + for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) { + if (tn->internal[i]) + has_data++; + } + + if (!has_data) { + file_struct->top = tn->internal[0]; + file_struct->top_level--; + yaffs_free_tnode(dev, tn); + } else { + done = 1; + } + } + + return YAFFS_OK; +} + +/*-------------------- End of File Structure functions.-------------------*/ + +/* alloc_empty_obj gets us a clean Object.*/ +static struct yaffs_obj *yaffs_alloc_empty_obj(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj = yaffs_alloc_raw_obj(dev); + + if (!obj) + return obj; + + dev->n_obj++; + + /* Now sweeten it up... */ + + memset(obj, 0, sizeof(struct yaffs_obj)); + obj->being_created = 1; + + obj->my_dev = dev; + obj->hdr_chunk = 0; + obj->variant_type = YAFFS_OBJECT_TYPE_UNKNOWN; + INIT_LIST_HEAD(&(obj->hard_links)); + INIT_LIST_HEAD(&(obj->hash_link)); + INIT_LIST_HEAD(&obj->siblings); + + /* Now make the directory sane */ + if (dev->root_dir) { + obj->parent = dev->root_dir; + list_add(&(obj->siblings), + &dev->root_dir->variant.dir_variant.children); + } + + /* Add it to the lost and found directory. + * NB Can't put root or lost-n-found in lost-n-found so + * check if lost-n-found exists first + */ + if (dev->lost_n_found) + yaffs_add_obj_to_dir(dev->lost_n_found, obj); + + obj->being_created = 0; + + dev->checkpoint_blocks_required = 0; /* force recalculation */ + + return obj; +} + +static int yaffs_find_nice_bucket(struct yaffs_dev *dev) +{ + int i; + int l = 999; + int lowest = 999999; + + /* Search for the shortest list or one that + * isn't too long. + */ + + for (i = 0; i < 10 && lowest > 4; i++) { + dev->bucket_finder++; + dev->bucket_finder %= YAFFS_NOBJECT_BUCKETS; + if (dev->obj_bucket[dev->bucket_finder].count < lowest) { + lowest = dev->obj_bucket[dev->bucket_finder].count; + l = dev->bucket_finder; + } + } + + return l; +} + +static int yaffs_new_obj_id(struct yaffs_dev *dev) +{ + int bucket = yaffs_find_nice_bucket(dev); + int found = 0; + struct list_head *i; + u32 n = (u32) bucket; + + /* Now find an object value that has not already been taken + * by scanning the list. + */ + + while (!found) { + found = 1; + n += YAFFS_NOBJECT_BUCKETS; + if (1 || dev->obj_bucket[bucket].count > 0) { + list_for_each(i, &dev->obj_bucket[bucket].list) { + /* If there is already one in the list */ + if (i && list_entry(i, struct yaffs_obj, + hash_link)->obj_id == n) { + found = 0; + } + } + } + } + return n; +} + +static void yaffs_hash_obj(struct yaffs_obj *in) +{ + int bucket = yaffs_hash_fn(in->obj_id); + struct yaffs_dev *dev = in->my_dev; + + list_add(&in->hash_link, &dev->obj_bucket[bucket].list); + dev->obj_bucket[bucket].count++; +} + +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number) +{ + int bucket = yaffs_hash_fn(number); + struct list_head *i; + struct yaffs_obj *in; + + list_for_each(i, &dev->obj_bucket[bucket].list) { + /* Look if it is in the list */ + in = list_entry(i, struct yaffs_obj, hash_link); + if (in->obj_id == number) { + /* Don't show if it is defered free */ + if (in->defered_free) + return NULL; + return in; + } + } + + return NULL; +} + +static struct yaffs_obj *yaffs_new_obj(struct yaffs_dev *dev, int number, + enum yaffs_obj_type type) +{ + struct yaffs_obj *the_obj = NULL; + struct yaffs_tnode *tn = NULL; + + if (number < 0) + number = yaffs_new_obj_id(dev); + + if (type == YAFFS_OBJECT_TYPE_FILE) { + tn = yaffs_get_tnode(dev); + if (!tn) + return NULL; + } + + the_obj = yaffs_alloc_empty_obj(dev); + if (!the_obj) { + if (tn) + yaffs_free_tnode(dev, tn); + return NULL; + } + + the_obj->fake = 0; + the_obj->rename_allowed = 1; + the_obj->unlink_allowed = 1; + the_obj->obj_id = number; + yaffs_hash_obj(the_obj); + the_obj->variant_type = type; + yaffs_load_current_time(the_obj, 1, 1); + + switch (type) { + case YAFFS_OBJECT_TYPE_FILE: + the_obj->variant.file_variant.file_size = 0; + the_obj->variant.file_variant.scanned_size = 0; + the_obj->variant.file_variant.shrink_size = + yaffs_max_file_size(dev); + the_obj->variant.file_variant.top_level = 0; + the_obj->variant.file_variant.top = tn; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + INIT_LIST_HEAD(&the_obj->variant.dir_variant.children); + INIT_LIST_HEAD(&the_obj->variant.dir_variant.dirty); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + case YAFFS_OBJECT_TYPE_HARDLINK: + case YAFFS_OBJECT_TYPE_SPECIAL: + /* No action required */ + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* todo this should not happen */ + break; + } + return the_obj; +} + +static struct yaffs_obj *yaffs_create_fake_dir(struct yaffs_dev *dev, + int number, u32 mode) +{ + + struct yaffs_obj *obj = + yaffs_new_obj(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY); + + if (!obj) + return NULL; + + obj->fake = 1; /* it is fake so it might not use NAND */ + obj->rename_allowed = 0; + obj->unlink_allowed = 0; + obj->deleted = 0; + obj->unlinked = 0; + obj->yst_mode = mode; + obj->my_dev = dev; + obj->hdr_chunk = 0; /* Not a valid chunk. */ + return obj; + +} + + +static void yaffs_init_tnodes_and_objs(struct yaffs_dev *dev) +{ + int i; + + dev->n_obj = 0; + dev->n_tnodes = 0; + yaffs_init_raw_tnodes_and_objs(dev); + + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { + INIT_LIST_HEAD(&dev->obj_bucket[i].list); + dev->obj_bucket[i].count = 0; + } +} + +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, + int number, + enum yaffs_obj_type type) +{ + struct yaffs_obj *the_obj = NULL; + + if (number > 0) + the_obj = yaffs_find_by_number(dev, number); + + if (!the_obj) + the_obj = yaffs_new_obj(dev, number, type); + + return the_obj; + +} + +YCHAR *yaffs_clone_str(const YCHAR *str) +{ + YCHAR *new_str = NULL; + int len; + + if (!str) + str = _Y(""); + + len = strnlen(str, YAFFS_MAX_ALIAS_LENGTH); + new_str = kmalloc((len + 1) * sizeof(YCHAR), GFP_NOFS); + if (new_str) { + strncpy(new_str, str, len); + new_str[len] = 0; + } + return new_str; + +} +/* + *yaffs_update_parent() handles fixing a directories mtime and ctime when a new + * link (ie. name) is created or deleted in the directory. + * + * ie. + * create dir/a : update dir's mtime/ctime + * rm dir/a: update dir's mtime/ctime + * modify dir/a: don't update dir's mtimme/ctime + * + * This can be handled immediately or defered. Defering helps reduce the number + * of updates when many files in a directory are changed within a brief period. + * + * If the directory updating is defered then yaffs_update_dirty_dirs must be + * called periodically. + */ + +static void yaffs_update_parent(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev; + + if (!obj) + return; + dev = obj->my_dev; + obj->dirty = 1; + yaffs_load_current_time(obj, 0, 1); + if (dev->param.defered_dir_update) { + struct list_head *link = &obj->variant.dir_variant.dirty; + + if (list_empty(link)) { + list_add(link, &dev->dirty_dirs); + yaffs_trace(YAFFS_TRACE_BACKGROUND, + "Added object %d to dirty directories", + obj->obj_id); + } + + } else { + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); + } +} + +void yaffs_update_dirty_dirs(struct yaffs_dev *dev) +{ + struct list_head *link; + struct yaffs_obj *obj; + struct yaffs_dir_var *d_s; + union yaffs_obj_var *o_v; + + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update dirty directories"); + + while (!list_empty(&dev->dirty_dirs)) { + link = dev->dirty_dirs.next; + list_del_init(link); + + d_s = list_entry(link, struct yaffs_dir_var, dirty); + o_v = list_entry(d_s, union yaffs_obj_var, dir_variant); + obj = list_entry(o_v, struct yaffs_obj, variant); + + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Update directory %d", + obj->obj_id); + + if (obj->dirty) + yaffs_update_oh(obj, NULL, 0, 0, 0, NULL); + } +} + +/* + * Mknod (create) a new object. + * equiv_obj only has meaning for a hard link; + * alias_str only has meaning for a symlink. + * rdev only has meaning for devices (a subset of special objects) + */ + +static struct yaffs_obj *yaffs_create_obj(enum yaffs_obj_type type, + struct yaffs_obj *parent, + const YCHAR *name, + u32 mode, + u32 uid, + u32 gid, + struct yaffs_obj *equiv_obj, + const YCHAR *alias_str, u32 rdev) +{ + struct yaffs_obj *in; + YCHAR *str = NULL; + struct yaffs_dev *dev = parent->my_dev; + + /* Check if the entry exists. + * If it does then fail the call since we don't want a dup. */ + if (yaffs_find_by_name(parent, name)) + return NULL; + + if (type == YAFFS_OBJECT_TYPE_SYMLINK) { + str = yaffs_clone_str(alias_str); + if (!str) + return NULL; + } + + in = yaffs_new_obj(dev, -1, type); + + if (!in) { + kfree(str); + return NULL; + } + + in->hdr_chunk = 0; + in->valid = 1; + in->variant_type = type; + + in->yst_mode = mode; + + yaffs_attribs_init(in, gid, uid, rdev); + + in->n_data_chunks = 0; + + yaffs_set_obj_name(in, name); + in->dirty = 1; + + yaffs_add_obj_to_dir(parent, in); + + in->my_dev = parent->my_dev; + + switch (type) { + case YAFFS_OBJECT_TYPE_SYMLINK: + in->variant.symlink_variant.alias = str; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant.hardlink_variant.equiv_obj = equiv_obj; + in->variant.hardlink_variant.equiv_id = equiv_obj->obj_id; + list_add(&in->hard_links, &equiv_obj->hard_links); + break; + case YAFFS_OBJECT_TYPE_FILE: + case YAFFS_OBJECT_TYPE_DIRECTORY: + case YAFFS_OBJECT_TYPE_SPECIAL: + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* do nothing */ + break; + } + + if (yaffs_update_oh(in, name, 0, 0, 0, NULL) < 0) { + /* Could not create the object header, fail */ + yaffs_del_obj(in); + in = NULL; + } + + if (in) + yaffs_update_parent(parent); + + return in; +} + +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_FILE, parent, name, mode, + uid, gid, NULL, NULL, 0); +} + +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, + u32 mode, u32 uid, u32 gid) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name, + mode, uid, gid, NULL, NULL, 0); +} + +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, u32 rdev) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode, + uid, gid, NULL, NULL, rdev); +} + +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, const YCHAR *alias) +{ + return yaffs_create_obj(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode, + uid, gid, NULL, alias, 0); +} + +/* yaffs_link_obj returns the object id of the equivalent object.*/ +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR * name, + struct yaffs_obj *equiv_obj) +{ + /* Get the real object in case we were fed a hard link obj */ + equiv_obj = yaffs_get_equivalent_obj(equiv_obj); + + if (yaffs_create_obj(YAFFS_OBJECT_TYPE_HARDLINK, + parent, name, 0, 0, 0, + equiv_obj, NULL, 0)) + return equiv_obj; + + return NULL; + +} + + + +/*---------------------- Block Management and Page Allocation -------------*/ + +static void yaffs_deinit_blocks(struct yaffs_dev *dev) +{ + if (dev->block_info_alt && dev->block_info) + vfree(dev->block_info); + else + kfree(dev->block_info); + + dev->block_info_alt = 0; + + dev->block_info = NULL; + + if (dev->chunk_bits_alt && dev->chunk_bits) + vfree(dev->chunk_bits); + else + kfree(dev->chunk_bits); + dev->chunk_bits_alt = 0; + dev->chunk_bits = NULL; +} + +static int yaffs_init_blocks(struct yaffs_dev *dev) +{ + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; + + dev->block_info = NULL; + dev->chunk_bits = NULL; + dev->alloc_block = -1; /* force it to get a new one */ + + /* If the first allocation strategy fails, thry the alternate one */ + dev->block_info = + kmalloc(n_blocks * sizeof(struct yaffs_block_info), GFP_NOFS); + if (!dev->block_info) { + dev->block_info = + vmalloc(n_blocks * sizeof(struct yaffs_block_info)); + dev->block_info_alt = 1; + } else { + dev->block_info_alt = 0; + } + + if (!dev->block_info) + goto alloc_error; + + /* Set up dynamic blockinfo stuff. Round up bytes. */ + dev->chunk_bit_stride = (dev->param.chunks_per_block + 7) / 8; + dev->chunk_bits = + kmalloc(dev->chunk_bit_stride * n_blocks, GFP_NOFS); + if (!dev->chunk_bits) { + dev->chunk_bits = + vmalloc(dev->chunk_bit_stride * n_blocks); + dev->chunk_bits_alt = 1; + } else { + dev->chunk_bits_alt = 0; + } + if (!dev->chunk_bits) + goto alloc_error; + + + memset(dev->block_info, 0, n_blocks * sizeof(struct yaffs_block_info)); + memset(dev->chunk_bits, 0, dev->chunk_bit_stride * n_blocks); + return YAFFS_OK; + +alloc_error: + yaffs_deinit_blocks(dev); + return YAFFS_FAIL; +} + + +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no) +{ + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block_no); + int erased_ok = 0; + int i; + + /* If the block is still healthy erase it and mark as clean. + * If the block has had a data failure, then retire it. + */ + + yaffs_trace(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE, + "yaffs_block_became_dirty block %d state %d %s", + block_no, bi->block_state, + (bi->needs_retiring) ? "needs retiring" : ""); + + yaffs2_clear_oldest_dirty_seq(dev, bi); + + bi->block_state = YAFFS_BLOCK_STATE_DIRTY; + + /* If this is the block being garbage collected then stop gc'ing */ + if (block_no == dev->gc_block) + dev->gc_block = 0; + + /* If this block is currently the best candidate for gc + * then drop as a candidate */ + if (block_no == dev->gc_dirtiest) { + dev->gc_dirtiest = 0; + dev->gc_pages_in_use = 0; + } + + if (!bi->needs_retiring) { + yaffs2_checkpt_invalidate(dev); + erased_ok = yaffs_erase_block(dev, block_no); + if (!erased_ok) { + dev->n_erase_failures++; + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>> Erasure failed %d", block_no); + } + } + + /* Verify erasure if needed */ + if (erased_ok && + ((yaffs_trace_mask & YAFFS_TRACE_ERASE) || + !yaffs_skip_verification(dev))) { + for (i = 0; i < dev->param.chunks_per_block; i++) { + if (!yaffs_check_chunk_erased(dev, + block_no * dev->param.chunks_per_block + i)) { + yaffs_trace(YAFFS_TRACE_ERROR, + ">>Block %d erasure supposedly OK, but chunk %d not erased", + block_no, i); + } + } + } + + if (!erased_ok) { + /* We lost a block of free space */ + dev->n_free_chunks -= dev->param.chunks_per_block; + yaffs_retire_block(dev, block_no); + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>> Block %d retired", block_no); + return; + } + + /* Clean it up... */ + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; + bi->seq_number = 0; + dev->n_erased_blocks++; + bi->pages_in_use = 0; + bi->soft_del_pages = 0; + bi->has_shrink_hdr = 0; + bi->skip_erased_check = 1; /* Clean, so no need to check */ + bi->gc_prioritise = 0; + bi->has_summary = 0; + + yaffs_clear_chunk_bits(dev, block_no); + + yaffs_trace(YAFFS_TRACE_ERASE, "Erased block %d", block_no); +} + +static inline int yaffs_gc_process_chunk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, + int old_chunk, u8 *buffer) +{ + int new_chunk; + int mark_flash = 1; + struct yaffs_ext_tags tags; + struct yaffs_obj *object; + int matching_chunk; + int ret_val = YAFFS_OK; + + memset(&tags, 0, sizeof(tags)); + yaffs_rd_chunk_tags_nand(dev, old_chunk, + buffer, &tags); + object = yaffs_find_by_number(dev, tags.obj_id); + + yaffs_trace(YAFFS_TRACE_GC_DETAIL, + "Collecting chunk in block %d, %d %d %d ", + dev->gc_chunk, tags.obj_id, + tags.chunk_id, tags.n_bytes); + + if (object && !yaffs_skip_verification(dev)) { + if (tags.chunk_id == 0) + matching_chunk = + object->hdr_chunk; + else if (object->soft_del) + /* Defeat the test */ + matching_chunk = old_chunk; + else + matching_chunk = + yaffs_find_chunk_in_file + (object, tags.chunk_id, + NULL); + + if (old_chunk != matching_chunk) + yaffs_trace(YAFFS_TRACE_ERROR, + "gc: page in gc mismatch: %d %d %d %d", + old_chunk, + matching_chunk, + tags.obj_id, + tags.chunk_id); + } + + if (!object) { + yaffs_trace(YAFFS_TRACE_ERROR, + "page %d in gc has no object: %d %d %d ", + old_chunk, + tags.obj_id, tags.chunk_id, + tags.n_bytes); + } + + if (object && + object->deleted && + object->soft_del && tags.chunk_id != 0) { + /* Data chunk in a soft deleted file, + * throw it away. + * It's a soft deleted data chunk, + * No need to copy this, just forget + * about it and fix up the object. + */ + + /* Free chunks already includes + * softdeleted chunks, how ever this + * chunk is going to soon be really + * deleted which will increment free + * chunks. We have to decrement free + * chunks so this works out properly. + */ + dev->n_free_chunks--; + bi->soft_del_pages--; + + object->n_data_chunks--; + if (object->n_data_chunks <= 0) { + /* remeber to clean up obj */ + dev->gc_cleanup_list[dev->n_clean_ups] = tags.obj_id; + dev->n_clean_ups++; + } + mark_flash = 0; + } else if (object) { + /* It's either a data chunk in a live + * file or an ObjectHeader, so we're + * interested in it. + * NB Need to keep the ObjectHeaders of + * deleted files until the whole file + * has been deleted off + */ + tags.serial_number++; + dev->n_gc_copies++; + + if (tags.chunk_id == 0) { + /* It is an object Id, + * We need to nuke the + * shrinkheader flags since its + * work is done. + * Also need to clean up + * shadowing. + */ + struct yaffs_obj_hdr *oh; + oh = (struct yaffs_obj_hdr *) buffer; + + oh->is_shrink = 0; + tags.extra_is_shrink = 0; + oh->shadows_obj = 0; + oh->inband_shadowed_obj_id = 0; + tags.extra_shadows = 0; + + /* Update file size */ + if (object->variant_type == YAFFS_OBJECT_TYPE_FILE) { + yaffs_oh_size_load(oh, + object->variant.file_variant.file_size); + tags.extra_file_size = + object->variant.file_variant.file_size; + } + + yaffs_verify_oh(object, oh, &tags, 1); + new_chunk = + yaffs_write_new_chunk(dev, (u8 *) oh, &tags, 1); + } else { + new_chunk = + yaffs_write_new_chunk(dev, buffer, &tags, 1); + } + + if (new_chunk < 0) { + ret_val = YAFFS_FAIL; + } else { + + /* Now fix up the Tnodes etc. */ + + if (tags.chunk_id == 0) { + /* It's a header */ + object->hdr_chunk = new_chunk; + object->serial = tags.serial_number; + } else { + /* It's a data chunk */ + yaffs_put_chunk_in_file(object, tags.chunk_id, + new_chunk, 0); + } + } + } + if (ret_val == YAFFS_OK) + yaffs_chunk_del(dev, old_chunk, mark_flash, __LINE__); + return ret_val; +} + +static int yaffs_gc_block(struct yaffs_dev *dev, int block, int whole_block) +{ + int old_chunk; + int ret_val = YAFFS_OK; + int i; + int is_checkpt_block; + int max_copies; + int chunks_before = yaffs_get_erased_chunks(dev); + int chunks_after; + struct yaffs_block_info *bi = yaffs_get_block_info(dev, block); + + is_checkpt_block = (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT); + + yaffs_trace(YAFFS_TRACE_TRACING, + "Collecting block %d, in use %d, shrink %d, whole_block %d", + block, bi->pages_in_use, bi->has_shrink_hdr, + whole_block); + + /*yaffs_verify_free_chunks(dev); */ + + if (bi->block_state == YAFFS_BLOCK_STATE_FULL) + bi->block_state = YAFFS_BLOCK_STATE_COLLECTING; + + bi->has_shrink_hdr = 0; /* clear the flag so that the block can erase */ + + dev->gc_disable = 1; + + yaffs_summary_gc(dev, block); + + if (is_checkpt_block || !yaffs_still_some_chunks(dev, block)) { + yaffs_trace(YAFFS_TRACE_TRACING, + "Collecting block %d that has no chunks in use", + block); + yaffs_block_became_dirty(dev, block); + } else { + + u8 *buffer = yaffs_get_temp_buffer(dev); + + yaffs_verify_blk(dev, bi, block); + + max_copies = (whole_block) ? dev->param.chunks_per_block : 5; + old_chunk = block * dev->param.chunks_per_block + dev->gc_chunk; + + for (/* init already done */ ; + ret_val == YAFFS_OK && + dev->gc_chunk < dev->param.chunks_per_block && + (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) && + max_copies > 0; + dev->gc_chunk++, old_chunk++) { + if (yaffs_check_chunk_bit(dev, block, dev->gc_chunk)) { + /* Page is in use and might need to be copied */ + max_copies--; + ret_val = yaffs_gc_process_chunk(dev, bi, + old_chunk, buffer); + } + } + yaffs_release_temp_buffer(dev, buffer); + } + + yaffs_verify_collected_blk(dev, bi, block); + + if (bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { + /* + * The gc did not complete. Set block state back to FULL + * because checkpointing does not restore gc. + */ + bi->block_state = YAFFS_BLOCK_STATE_FULL; + } else { + /* The gc completed. */ + /* Do any required cleanups */ + for (i = 0; i < dev->n_clean_ups; i++) { + /* Time to delete the file too */ + struct yaffs_obj *object = + yaffs_find_by_number(dev, dev->gc_cleanup_list[i]); + if (object) { + yaffs_free_tnode(dev, + object->variant.file_variant.top); + object->variant.file_variant.top = NULL; + yaffs_trace(YAFFS_TRACE_GC, + "yaffs: About to finally delete object %d", + object->obj_id); + yaffs_generic_obj_del(object); + object->my_dev->n_deleted_files--; + } + + } + chunks_after = yaffs_get_erased_chunks(dev); + if (chunks_before >= chunks_after) + yaffs_trace(YAFFS_TRACE_GC, + "gc did not increase free chunks before %d after %d", + chunks_before, chunks_after); + dev->gc_block = 0; + dev->gc_chunk = 0; + dev->n_clean_ups = 0; + } + + dev->gc_disable = 0; + + return ret_val; +} + +/* + * find_gc_block() selects the dirtiest block (or close enough) + * for garbage collection. + */ + +static unsigned yaffs_find_gc_block(struct yaffs_dev *dev, + int aggressive, int background) +{ + int i; + int iterations; + unsigned selected = 0; + int prioritised = 0; + int prioritised_exist = 0; + struct yaffs_block_info *bi; + int threshold; + + /* First let's see if we need to grab a prioritised block */ + if (dev->has_pending_prioritised_gc && !aggressive) { + dev->gc_dirtiest = 0; + bi = dev->block_info; + for (i = dev->internal_start_block; + i <= dev->internal_end_block && !selected; i++) { + + if (bi->gc_prioritise) { + prioritised_exist = 1; + if (bi->block_state == YAFFS_BLOCK_STATE_FULL && + yaffs_block_ok_for_gc(dev, bi)) { + selected = i; + prioritised = 1; + } + } + bi++; + } + + /* + * If there is a prioritised block and none was selected then + * this happened because there is at least one old dirty block + * gumming up the works. Let's gc the oldest dirty block. + */ + + if (prioritised_exist && + !selected && dev->oldest_dirty_block > 0) + selected = dev->oldest_dirty_block; + + if (!prioritised_exist) /* None found, so we can clear this */ + dev->has_pending_prioritised_gc = 0; + } + + /* If we're doing aggressive GC then we are happy to take a less-dirty + * block, and search harder. + * else (leasurely gc), then we only bother to do this if the + * block has only a few pages in use. + */ + + if (!selected) { + int pages_used; + int n_blocks = + dev->internal_end_block - dev->internal_start_block + 1; + if (aggressive) { + threshold = dev->param.chunks_per_block; + iterations = n_blocks; + } else { + int max_threshold; + + if (background) + max_threshold = dev->param.chunks_per_block / 2; + else + max_threshold = dev->param.chunks_per_block / 8; + + if (max_threshold < YAFFS_GC_PASSIVE_THRESHOLD) + max_threshold = YAFFS_GC_PASSIVE_THRESHOLD; + + threshold = background ? (dev->gc_not_done + 2) * 2 : 0; + if (threshold < YAFFS_GC_PASSIVE_THRESHOLD) + threshold = YAFFS_GC_PASSIVE_THRESHOLD; + if (threshold > max_threshold) + threshold = max_threshold; + + iterations = n_blocks / 16 + 1; + if (iterations > 100) + iterations = 100; + } + + for (i = 0; + i < iterations && + (dev->gc_dirtiest < 1 || + dev->gc_pages_in_use > YAFFS_GC_GOOD_ENOUGH); + i++) { + dev->gc_block_finder++; + if (dev->gc_block_finder < dev->internal_start_block || + dev->gc_block_finder > dev->internal_end_block) + dev->gc_block_finder = + dev->internal_start_block; + + bi = yaffs_get_block_info(dev, dev->gc_block_finder); + + pages_used = bi->pages_in_use - bi->soft_del_pages; + + if (bi->block_state == YAFFS_BLOCK_STATE_FULL && + pages_used < dev->param.chunks_per_block && + (dev->gc_dirtiest < 1 || + pages_used < dev->gc_pages_in_use) && + yaffs_block_ok_for_gc(dev, bi)) { + dev->gc_dirtiest = dev->gc_block_finder; + dev->gc_pages_in_use = pages_used; + } + } + + if (dev->gc_dirtiest > 0 && dev->gc_pages_in_use <= threshold) + selected = dev->gc_dirtiest; + } + + /* + * If nothing has been selected for a while, try the oldest dirty + * because that's gumming up the works. + */ + + if (!selected && dev->param.is_yaffs2 && + dev->gc_not_done >= (background ? 10 : 20)) { + yaffs2_find_oldest_dirty_seq(dev); + if (dev->oldest_dirty_block > 0) { + selected = dev->oldest_dirty_block; + dev->gc_dirtiest = selected; + dev->oldest_dirty_gc_count++; + bi = yaffs_get_block_info(dev, selected); + dev->gc_pages_in_use = + bi->pages_in_use - bi->soft_del_pages; + } else { + dev->gc_not_done = 0; + } + } + + if (selected) { + yaffs_trace(YAFFS_TRACE_GC, + "GC Selected block %d with %d free, prioritised:%d", + selected, + dev->param.chunks_per_block - dev->gc_pages_in_use, + prioritised); + + dev->n_gc_blocks++; + if (background) + dev->bg_gcs++; + + dev->gc_dirtiest = 0; + dev->gc_pages_in_use = 0; + dev->gc_not_done = 0; + if (dev->refresh_skip > 0) + dev->refresh_skip--; + } else { + dev->gc_not_done++; + yaffs_trace(YAFFS_TRACE_GC, + "GC none: finder %d skip %d threshold %d dirtiest %d using %d oldest %d%s", + dev->gc_block_finder, dev->gc_not_done, threshold, + dev->gc_dirtiest, dev->gc_pages_in_use, + dev->oldest_dirty_block, background ? " bg" : ""); + } + + return selected; +} + +/* New garbage collector + * If we're very low on erased blocks then we do aggressive garbage collection + * otherwise we do "leasurely" garbage collection. + * Aggressive gc looks further (whole array) and will accept less dirty blocks. + * Passive gc only inspects smaller areas and only accepts more dirty blocks. + * + * The idea is to help clear out space in a more spread-out manner. + * Dunno if it really does anything useful. + */ +static int yaffs_check_gc(struct yaffs_dev *dev, int background) +{ + int aggressive = 0; + int gc_ok = YAFFS_OK; + int max_tries = 0; + int min_erased; + int erased_chunks; + int checkpt_block_adjust; + + if (dev->param.gc_control && (dev->param.gc_control(dev) & 1) == 0) + return YAFFS_OK; + + if (dev->gc_disable) + /* Bail out so we don't get recursive gc */ + return YAFFS_OK; + + /* This loop should pass the first time. + * Only loops here if the collection does not increase space. + */ + + do { + max_tries++; + + checkpt_block_adjust = yaffs_calc_checkpt_blocks_required(dev); + + min_erased = + dev->param.n_reserved_blocks + checkpt_block_adjust + 1; + erased_chunks = + dev->n_erased_blocks * dev->param.chunks_per_block; + + /* If we need a block soon then do aggressive gc. */ + if (dev->n_erased_blocks < min_erased) + aggressive = 1; + else { + if (!background + && erased_chunks > (dev->n_free_chunks / 4)) + break; + + if (dev->gc_skip > 20) + dev->gc_skip = 20; + if (erased_chunks < dev->n_free_chunks / 2 || + dev->gc_skip < 1 || background) + aggressive = 0; + else { + dev->gc_skip--; + break; + } + } + + dev->gc_skip = 5; + + /* If we don't already have a block being gc'd then see if we + * should start another */ + + if (dev->gc_block < 1 && !aggressive) { + dev->gc_block = yaffs2_find_refresh_block(dev); + dev->gc_chunk = 0; + dev->n_clean_ups = 0; + } + if (dev->gc_block < 1) { + dev->gc_block = + yaffs_find_gc_block(dev, aggressive, background); + dev->gc_chunk = 0; + dev->n_clean_ups = 0; + } + + if (dev->gc_block > 0) { + dev->all_gcs++; + if (!aggressive) + dev->passive_gc_count++; + + yaffs_trace(YAFFS_TRACE_GC, + "yaffs: GC n_erased_blocks %d aggressive %d", + dev->n_erased_blocks, aggressive); + + gc_ok = yaffs_gc_block(dev, dev->gc_block, aggressive); + } + + if (dev->n_erased_blocks < (dev->param.n_reserved_blocks) && + dev->gc_block > 0) { + yaffs_trace(YAFFS_TRACE_GC, + "yaffs: GC !!!no reclaim!!! n_erased_blocks %d after try %d block %d", + dev->n_erased_blocks, max_tries, + dev->gc_block); + } + } while ((dev->n_erased_blocks < dev->param.n_reserved_blocks) && + (dev->gc_block > 0) && (max_tries < 2)); + + return aggressive ? gc_ok : YAFFS_OK; +} + +/* + * yaffs_bg_gc() + * Garbage collects. Intended to be called from a background thread. + * Returns non-zero if at least half the free chunks are erased. + */ +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency) +{ + int erased_chunks = dev->n_erased_blocks * dev->param.chunks_per_block; + + yaffs_trace(YAFFS_TRACE_BACKGROUND, "Background gc %u", urgency); + + yaffs_check_gc(dev, 1); + return erased_chunks > dev->n_free_chunks / 2; +} + +/*-------------------- Data file manipulation -----------------*/ + +static int yaffs_rd_data_obj(struct yaffs_obj *in, int inode_chunk, u8 * buffer) +{ + int nand_chunk = yaffs_find_chunk_in_file(in, inode_chunk, NULL); + + if (nand_chunk >= 0) + return yaffs_rd_chunk_tags_nand(in->my_dev, nand_chunk, + buffer, NULL); + else { + yaffs_trace(YAFFS_TRACE_NANDACCESS, + "Chunk %d not found zero instead", + nand_chunk); + /* get sane (zero) data if you read a hole */ + memset(buffer, 0, in->my_dev->data_bytes_per_chunk); + return 0; + } + +} + +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, + int lyn) +{ + int block; + int page; + struct yaffs_ext_tags tags; + struct yaffs_block_info *bi; + + if (chunk_id <= 0) + return; + + dev->n_deletions++; + block = chunk_id / dev->param.chunks_per_block; + page = chunk_id % dev->param.chunks_per_block; + + if (!yaffs_check_chunk_bit(dev, block, page)) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Deleting invalid chunk %d", chunk_id); + + bi = yaffs_get_block_info(dev, block); + + yaffs2_update_oldest_dirty_seq(dev, block, bi); + + yaffs_trace(YAFFS_TRACE_DELETION, + "line %d delete of chunk %d", + lyn, chunk_id); + + if (!dev->param.is_yaffs2 && mark_flash && + bi->block_state != YAFFS_BLOCK_STATE_COLLECTING) { + + memset(&tags, 0, sizeof(tags)); + tags.is_deleted = 1; + yaffs_wr_chunk_tags_nand(dev, chunk_id, NULL, &tags); + yaffs_handle_chunk_update(dev, chunk_id, &tags); + } else { + dev->n_unmarked_deletions++; + } + + /* Pull out of the management area. + * If the whole block became dirty, this will kick off an erasure. + */ + if (bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING || + bi->block_state == YAFFS_BLOCK_STATE_FULL || + bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || + bi->block_state == YAFFS_BLOCK_STATE_COLLECTING) { + dev->n_free_chunks++; + yaffs_clear_chunk_bit(dev, block, page); + bi->pages_in_use--; + + if (bi->pages_in_use == 0 && + !bi->has_shrink_hdr && + bi->block_state != YAFFS_BLOCK_STATE_ALLOCATING && + bi->block_state != YAFFS_BLOCK_STATE_NEEDS_SCAN) { + yaffs_block_became_dirty(dev, block); + } + } +} + +static int yaffs_wr_data_obj(struct yaffs_obj *in, int inode_chunk, + const u8 *buffer, int n_bytes, int use_reserve) +{ + /* Find old chunk Need to do this to get serial number + * Write new one and patch into tree. + * Invalidate old tags. + */ + + int prev_chunk_id; + struct yaffs_ext_tags prev_tags; + int new_chunk_id; + struct yaffs_ext_tags new_tags; + struct yaffs_dev *dev = in->my_dev; + + yaffs_check_gc(dev, 0); + + /* Get the previous chunk at this location in the file if it exists. + * If it does not exist then put a zero into the tree. This creates + * the tnode now, rather than later when it is harder to clean up. + */ + prev_chunk_id = yaffs_find_chunk_in_file(in, inode_chunk, &prev_tags); + if (prev_chunk_id < 1 && + !yaffs_put_chunk_in_file(in, inode_chunk, 0, 0)) + return 0; + + /* Set up new tags */ + memset(&new_tags, 0, sizeof(new_tags)); + + new_tags.chunk_id = inode_chunk; + new_tags.obj_id = in->obj_id; + new_tags.serial_number = + (prev_chunk_id > 0) ? prev_tags.serial_number + 1 : 1; + new_tags.n_bytes = n_bytes; + + if (n_bytes < 1 || n_bytes > dev->param.total_bytes_per_chunk) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Writing %d bytes to chunk!!!!!!!!!", + n_bytes); + BUG(); + } + + new_chunk_id = + yaffs_write_new_chunk(dev, buffer, &new_tags, use_reserve); + + if (new_chunk_id > 0) { + yaffs_put_chunk_in_file(in, inode_chunk, new_chunk_id, 0); + + if (prev_chunk_id > 0) + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); + + yaffs_verify_file_sane(in); + } + return new_chunk_id; + +} + + + +static int yaffs_do_xattrib_mod(struct yaffs_obj *obj, int set, + const YCHAR *name, const void *value, int size, + int flags) +{ + struct yaffs_xattr_mod xmod; + int result; + + xmod.set = set; + xmod.name = name; + xmod.data = value; + xmod.size = size; + xmod.flags = flags; + xmod.result = -ENOSPC; + + result = yaffs_update_oh(obj, NULL, 0, 0, 0, &xmod); + + if (result > 0) + return xmod.result; + else + return -ENOSPC; +} + +static int yaffs_apply_xattrib_mod(struct yaffs_obj *obj, char *buffer, + struct yaffs_xattr_mod *xmod) +{ + int retval = 0; + int x_offs = sizeof(struct yaffs_obj_hdr); + struct yaffs_dev *dev = obj->my_dev; + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); + char *x_buffer = buffer + x_offs; + + if (xmod->set) + retval = + nval_set(x_buffer, x_size, xmod->name, xmod->data, + xmod->size, xmod->flags); + else + retval = nval_del(x_buffer, x_size, xmod->name); + + obj->has_xattr = nval_hasvalues(x_buffer, x_size); + obj->xattr_known = 1; + xmod->result = retval; + + return retval; +} + +static int yaffs_do_xattrib_fetch(struct yaffs_obj *obj, const YCHAR *name, + void *value, int size) +{ + char *buffer = NULL; + int result; + struct yaffs_ext_tags tags; + struct yaffs_dev *dev = obj->my_dev; + int x_offs = sizeof(struct yaffs_obj_hdr); + int x_size = dev->data_bytes_per_chunk - sizeof(struct yaffs_obj_hdr); + char *x_buffer; + int retval = 0; + + if (obj->hdr_chunk < 1) + return -ENODATA; + + /* If we know that the object has no xattribs then don't do all the + * reading and parsing. + */ + if (obj->xattr_known && !obj->has_xattr) { + if (name) + return -ENODATA; + else + return 0; + } + + buffer = (char *)yaffs_get_temp_buffer(dev); + if (!buffer) + return -ENOMEM; + + result = + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, (u8 *) buffer, &tags); + + if (result != YAFFS_OK) + retval = -ENOENT; + else { + x_buffer = buffer + x_offs; + + if (!obj->xattr_known) { + obj->has_xattr = nval_hasvalues(x_buffer, x_size); + obj->xattr_known = 1; + } + + if (name) + retval = nval_get(x_buffer, x_size, name, value, size); + else + retval = nval_list(x_buffer, x_size, value, size); + } + yaffs_release_temp_buffer(dev, (u8 *) buffer); + return retval; +} + +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR * name, + const void *value, int size, int flags) +{ + return yaffs_do_xattrib_mod(obj, 1, name, value, size, flags); +} + +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR * name) +{ + return yaffs_do_xattrib_mod(obj, 0, name, NULL, 0, 0); +} + +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR * name, void *value, + int size) +{ + return yaffs_do_xattrib_fetch(obj, name, value, size); +} + +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size) +{ + return yaffs_do_xattrib_fetch(obj, NULL, buffer, size); +} + +static void yaffs_check_obj_details_loaded(struct yaffs_obj *in) +{ + u8 *buf; + struct yaffs_obj_hdr *oh; + struct yaffs_dev *dev; + struct yaffs_ext_tags tags; + int result; + int alloc_failed = 0; + + if (!in || !in->lazy_loaded || in->hdr_chunk < 1) + return; + + dev = in->my_dev; + in->lazy_loaded = 0; + buf = yaffs_get_temp_buffer(dev); + + result = yaffs_rd_chunk_tags_nand(dev, in->hdr_chunk, buf, &tags); + oh = (struct yaffs_obj_hdr *)buf; + + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + yaffs_set_obj_name_from_oh(in, oh); + + if (in->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { + in->variant.symlink_variant.alias = + yaffs_clone_str(oh->alias); + if (!in->variant.symlink_variant.alias) + alloc_failed = 1; /* Not returned */ + } + yaffs_release_temp_buffer(dev, buf); +} + +static void yaffs_load_name_from_oh(struct yaffs_dev *dev, YCHAR *name, + const YCHAR *oh_name, int buff_size) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + if (dev->param.auto_unicode) { + if (*oh_name) { + /* It is an ASCII name, do an ASCII to + * unicode conversion */ + const char *ascii_oh_name = (const char *)oh_name; + int n = buff_size - 1; + while (n > 0 && *ascii_oh_name) { + *name = *ascii_oh_name; + name++; + ascii_oh_name++; + n--; + } + } else { + strncpy(name, oh_name + 1, buff_size - 1); + } + } else { +#else + (void) dev; + { +#endif + strncpy(name, oh_name, buff_size - 1); + } +} + +static void yaffs_load_oh_from_name(struct yaffs_dev *dev, YCHAR *oh_name, + const YCHAR *name) +{ +#ifdef CONFIG_YAFFS_AUTO_UNICODE + + int is_ascii; + YCHAR *w; + + if (dev->param.auto_unicode) { + + is_ascii = 1; + w = name; + + /* Figure out if the name will fit in ascii character set */ + while (is_ascii && *w) { + if ((*w) & 0xff00) + is_ascii = 0; + w++; + } + + if (is_ascii) { + /* It is an ASCII name, so convert unicode to ascii */ + char *ascii_oh_name = (char *)oh_name; + int n = YAFFS_MAX_NAME_LENGTH - 1; + while (n > 0 && *name) { + *ascii_oh_name = *name; + name++; + ascii_oh_name++; + n--; + } + } else { + /* Unicode name, so save starting at the second YCHAR */ + *oh_name = 0; + strncpy(oh_name + 1, name, YAFFS_MAX_NAME_LENGTH - 2); + } + } else { +#else + dev = dev; + { +#endif + strncpy(oh_name, name, YAFFS_MAX_NAME_LENGTH - 1); + } +} + +/* UpdateObjectHeader updates the header on NAND for an object. + * If name is not NULL, then that new name is used. + */ +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, int force, + int is_shrink, int shadows, struct yaffs_xattr_mod *xmod) +{ + + struct yaffs_block_info *bi; + struct yaffs_dev *dev = in->my_dev; + int prev_chunk_id; + int ret_val = 0; + int result = 0; + int new_chunk_id; + struct yaffs_ext_tags new_tags; + struct yaffs_ext_tags old_tags; + const YCHAR *alias = NULL; + u8 *buffer = NULL; + YCHAR old_name[YAFFS_MAX_NAME_LENGTH + 1]; + struct yaffs_obj_hdr *oh = NULL; + loff_t file_size = 0; + + strcpy(old_name, _Y("silly old name")); + + if (in->fake && in != dev->root_dir && !force && !xmod) + return ret_val; + + yaffs_check_gc(dev, 0); + yaffs_check_obj_details_loaded(in); + + buffer = yaffs_get_temp_buffer(in->my_dev); + oh = (struct yaffs_obj_hdr *)buffer; + + prev_chunk_id = in->hdr_chunk; + + if (prev_chunk_id > 0) { + result = yaffs_rd_chunk_tags_nand(dev, prev_chunk_id, + buffer, &old_tags); + + yaffs_verify_oh(in, oh, &old_tags, 0); + memcpy(old_name, oh->name, sizeof(oh->name)); + memset(buffer, 0xff, sizeof(struct yaffs_obj_hdr)); + } else { + memset(buffer, 0xff, dev->data_bytes_per_chunk); + } + + oh->type = in->variant_type; + oh->yst_mode = in->yst_mode; + oh->shadows_obj = oh->inband_shadowed_obj_id = shadows; + + yaffs_load_attribs_oh(oh, in); + + if (in->parent) + oh->parent_obj_id = in->parent->obj_id; + else + oh->parent_obj_id = 0; + + if (name && *name) { + memset(oh->name, 0, sizeof(oh->name)); + yaffs_load_oh_from_name(dev, oh->name, name); + } else if (prev_chunk_id > 0) { + memcpy(oh->name, old_name, sizeof(oh->name)); + } else { + memset(oh->name, 0, sizeof(oh->name)); + } + + oh->is_shrink = is_shrink; + + switch (in->variant_type) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Should not happen */ + break; + case YAFFS_OBJECT_TYPE_FILE: + if (oh->parent_obj_id != YAFFS_OBJECTID_DELETED && + oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED) + file_size = in->variant.file_variant.file_size; + yaffs_oh_size_load(oh, file_size); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + oh->equiv_id = in->variant.hardlink_variant.equiv_id; + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + alias = in->variant.symlink_variant.alias; + if (!alias) + alias = _Y("no alias"); + strncpy(oh->alias, alias, YAFFS_MAX_ALIAS_LENGTH); + oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0; + break; + } + + /* process any xattrib modifications */ + if (xmod) + yaffs_apply_xattrib_mod(in, (char *)buffer, xmod); + + /* Tags */ + memset(&new_tags, 0, sizeof(new_tags)); + in->serial++; + new_tags.chunk_id = 0; + new_tags.obj_id = in->obj_id; + new_tags.serial_number = in->serial; + + /* Add extra info for file header */ + new_tags.extra_available = 1; + new_tags.extra_parent_id = oh->parent_obj_id; + new_tags.extra_file_size = file_size; + new_tags.extra_is_shrink = oh->is_shrink; + new_tags.extra_equiv_id = oh->equiv_id; + new_tags.extra_shadows = (oh->shadows_obj > 0) ? 1 : 0; + new_tags.extra_obj_type = in->variant_type; + yaffs_verify_oh(in, oh, &new_tags, 1); + + /* Create new chunk in NAND */ + new_chunk_id = + yaffs_write_new_chunk(dev, buffer, &new_tags, + (prev_chunk_id > 0) ? 1 : 0); + + if (buffer) + yaffs_release_temp_buffer(dev, buffer); + + if (new_chunk_id < 0) + return new_chunk_id; + + in->hdr_chunk = new_chunk_id; + + if (prev_chunk_id > 0) + yaffs_chunk_del(dev, prev_chunk_id, 1, __LINE__); + + if (!yaffs_obj_cache_dirty(in)) + in->dirty = 0; + + /* If this was a shrink, then mark the block + * that the chunk lives on */ + if (is_shrink) { + bi = yaffs_get_block_info(in->my_dev, + new_chunk_id / + in->my_dev->param.chunks_per_block); + bi->has_shrink_hdr = 1; + } + + + return new_chunk_id; +} + +/*--------------------- File read/write ------------------------ + * Read and write have very similar structures. + * In general the read/write has three parts to it + * An incomplete chunk to start with (if the read/write is not chunk-aligned) + * Some complete chunks + * An incomplete chunk to end off with + * + * Curve-balls: the first chunk might also be the last chunk. + */ + +int yaffs_file_rd(struct yaffs_obj *in, u8 * buffer, loff_t offset, int n_bytes) +{ + int chunk; + u32 start; + int n_copy; + int n = n_bytes; + int n_done = 0; + struct yaffs_cache *cache; + struct yaffs_dev *dev; + + dev = in->my_dev; + + while (n > 0) { + yaffs_addr_to_chunk(dev, offset, &chunk, &start); + chunk++; + + /* OK now check for the curveball where the start and end are in + * the same chunk. + */ + if ((start + n) < dev->data_bytes_per_chunk) + n_copy = n; + else + n_copy = dev->data_bytes_per_chunk - start; + + cache = yaffs_find_chunk_cache(in, chunk); + + /* If the chunk is already in the cache or it is less than + * a whole chunk or we're using inband tags then use the cache + * (if there is caching) else bypass the cache. + */ + if (cache || n_copy != dev->data_bytes_per_chunk || + dev->param.inband_tags) { + if (dev->param.n_caches > 0) { + + /* If we can't find the data in the cache, + * then load it up. */ + + if (!cache) { + cache = + yaffs_grab_chunk_cache(in->my_dev); + cache->object = in; + cache->chunk_id = chunk; + cache->dirty = 0; + cache->locked = 0; + yaffs_rd_data_obj(in, chunk, + cache->data); + cache->n_bytes = 0; + } + + yaffs_use_cache(dev, cache, 0); + + cache->locked = 1; + + memcpy(buffer, &cache->data[start], n_copy); + + cache->locked = 0; + } else { + /* Read into the local buffer then copy.. */ + + u8 *local_buffer = + yaffs_get_temp_buffer(dev); + yaffs_rd_data_obj(in, chunk, local_buffer); + + memcpy(buffer, &local_buffer[start], n_copy); + + yaffs_release_temp_buffer(dev, local_buffer); + } + } else { + /* A full chunk. Read directly into the buffer. */ + yaffs_rd_data_obj(in, chunk, buffer); + } + n -= n_copy; + offset += n_copy; + buffer += n_copy; + n_done += n_copy; + } + return n_done; +} + +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, + int n_bytes, int write_through) +{ + + int chunk; + u32 start; + int n_copy; + int n = n_bytes; + int n_done = 0; + int n_writeback; + loff_t start_write = offset; + int chunk_written = 0; + u32 n_bytes_read; + loff_t chunk_start; + struct yaffs_dev *dev; + + dev = in->my_dev; + + while (n > 0 && chunk_written >= 0) { + yaffs_addr_to_chunk(dev, offset, &chunk, &start); + + if (((loff_t)chunk) * + dev->data_bytes_per_chunk + start != offset || + start >= dev->data_bytes_per_chunk) { + yaffs_trace(YAFFS_TRACE_ERROR, + "AddrToChunk of offset %lld gives chunk %d start %d", + offset, chunk, start); + } + chunk++; /* File pos to chunk in file offset */ + + /* OK now check for the curveball where the start and end are in + * the same chunk. + */ + + if ((start + n) < dev->data_bytes_per_chunk) { + n_copy = n; + + /* Now calculate how many bytes to write back.... + * If we're overwriting and not writing to then end of + * file then we need to write back as much as was there + * before. + */ + + chunk_start = (((loff_t)(chunk - 1)) * + dev->data_bytes_per_chunk); + + if (chunk_start > in->variant.file_variant.file_size) + n_bytes_read = 0; /* Past end of file */ + else + n_bytes_read = + in->variant.file_variant.file_size - + chunk_start; + + if (n_bytes_read > dev->data_bytes_per_chunk) + n_bytes_read = dev->data_bytes_per_chunk; + + n_writeback = + (n_bytes_read > + (start + n)) ? n_bytes_read : (start + n); + + if (n_writeback < 0 || + n_writeback > dev->data_bytes_per_chunk) + BUG(); + + } else { + n_copy = dev->data_bytes_per_chunk - start; + n_writeback = dev->data_bytes_per_chunk; + } + + if (n_copy != dev->data_bytes_per_chunk || + dev->param.inband_tags) { + /* An incomplete start or end chunk (or maybe both + * start and end chunk), or we're using inband tags, + * so we want to use the cache buffers. + */ + if (dev->param.n_caches > 0) { + struct yaffs_cache *cache; + + /* If we can't find the data in the cache, then + * load the cache */ + cache = yaffs_find_chunk_cache(in, chunk); + + if (!cache && + yaffs_check_alloc_available(dev, 1)) { + cache = yaffs_grab_chunk_cache(dev); + cache->object = in; + cache->chunk_id = chunk; + cache->dirty = 0; + cache->locked = 0; + yaffs_rd_data_obj(in, chunk, + cache->data); + } else if (cache && + !cache->dirty && + !yaffs_check_alloc_available(dev, + 1)) { + /* Drop the cache if it was a read cache + * item and no space check has been made + * for it. + */ + cache = NULL; + } + + if (cache) { + yaffs_use_cache(dev, cache, 1); + cache->locked = 1; + + memcpy(&cache->data[start], buffer, + n_copy); + + cache->locked = 0; + cache->n_bytes = n_writeback; + + if (write_through) { + chunk_written = + yaffs_wr_data_obj + (cache->object, + cache->chunk_id, + cache->data, + cache->n_bytes, 1); + cache->dirty = 0; + } + } else { + chunk_written = -1; /* fail write */ + } + } else { + /* An incomplete start or end chunk (or maybe + * both start and end chunk). Read into the + * local buffer then copy over and write back. + */ + + u8 *local_buffer = yaffs_get_temp_buffer(dev); + + yaffs_rd_data_obj(in, chunk, local_buffer); + memcpy(&local_buffer[start], buffer, n_copy); + + chunk_written = + yaffs_wr_data_obj(in, chunk, + local_buffer, + n_writeback, 0); + + yaffs_release_temp_buffer(dev, local_buffer); + } + } else { + /* A full chunk. Write directly from the buffer. */ + + chunk_written = + yaffs_wr_data_obj(in, chunk, buffer, + dev->data_bytes_per_chunk, 0); + + /* Since we've overwritten the cached data, + * we better invalidate it. */ + yaffs_invalidate_chunk_cache(in, chunk); + } + + if (chunk_written >= 0) { + n -= n_copy; + offset += n_copy; + buffer += n_copy; + n_done += n_copy; + } + } + + /* Update file object */ + + if ((start_write + n_done) > in->variant.file_variant.file_size) + in->variant.file_variant.file_size = (start_write + n_done); + + in->dirty = 1; + return n_done; +} + +int yaffs_wr_file(struct yaffs_obj *in, const u8 *buffer, loff_t offset, + int n_bytes, int write_through) +{ + yaffs2_handle_hole(in, offset); + return yaffs_do_file_wr(in, buffer, offset, n_bytes, write_through); +} + +/* ---------------------- File resizing stuff ------------------ */ + +static void yaffs_prune_chunks(struct yaffs_obj *in, loff_t new_size) +{ + + struct yaffs_dev *dev = in->my_dev; + loff_t old_size = in->variant.file_variant.file_size; + int i; + int chunk_id; + u32 dummy; + int last_del; + int start_del; + + if (old_size > 0) + yaffs_addr_to_chunk(dev, old_size - 1, &last_del, &dummy); + else + last_del = 0; + + yaffs_addr_to_chunk(dev, new_size + dev->data_bytes_per_chunk - 1, + &start_del, &dummy); + last_del++; + start_del++; + + /* Delete backwards so that we don't end up with holes if + * power is lost part-way through the operation. + */ + for (i = last_del; i >= start_del; i--) { + /* NB this could be optimised somewhat, + * eg. could retrieve the tags and write them without + * using yaffs_chunk_del + */ + + chunk_id = yaffs_find_del_file_chunk(in, i, NULL); + + if (chunk_id < 1) + continue; + + if (chunk_id < + (dev->internal_start_block * dev->param.chunks_per_block) || + chunk_id >= + ((dev->internal_end_block + 1) * + dev->param.chunks_per_block)) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Found daft chunk_id %d for %d", + chunk_id, i); + } else { + in->n_data_chunks--; + yaffs_chunk_del(dev, chunk_id, 1, __LINE__); + } + } +} + +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size) +{ + int new_full; + u32 new_partial; + struct yaffs_dev *dev = obj->my_dev; + + yaffs_addr_to_chunk(dev, new_size, &new_full, &new_partial); + + yaffs_prune_chunks(obj, new_size); + + if (new_partial != 0) { + int last_chunk = 1 + new_full; + u8 *local_buffer = yaffs_get_temp_buffer(dev); + + /* Rewrite the last chunk with its new size and zero pad */ + yaffs_rd_data_obj(obj, last_chunk, local_buffer); + memset(local_buffer + new_partial, 0, + dev->data_bytes_per_chunk - new_partial); + + yaffs_wr_data_obj(obj, last_chunk, local_buffer, + new_partial, 1); + + yaffs_release_temp_buffer(dev, local_buffer); + } + + obj->variant.file_variant.file_size = new_size; + + yaffs_prune_tree(dev, &obj->variant.file_variant); +} + +int yaffs_resize_file(struct yaffs_obj *in, loff_t new_size) +{ + struct yaffs_dev *dev = in->my_dev; + loff_t old_size = in->variant.file_variant.file_size; + + yaffs_flush_file_cache(in); + yaffs_invalidate_whole_cache(in); + + yaffs_check_gc(dev, 0); + + if (in->variant_type != YAFFS_OBJECT_TYPE_FILE) + return YAFFS_FAIL; + + if (new_size == old_size) + return YAFFS_OK; + + if (new_size > old_size) { + yaffs2_handle_hole(in, new_size); + in->variant.file_variant.file_size = new_size; + } else { + /* new_size < old_size */ + yaffs_resize_file_down(in, new_size); + } + + /* Write a new object header to reflect the resize. + * show we've shrunk the file, if need be + * Do this only if the file is not in the deleted directories + * and is not shadowed. + */ + if (in->parent && + !in->is_shadowed && + in->parent->obj_id != YAFFS_OBJECTID_UNLINKED && + in->parent->obj_id != YAFFS_OBJECTID_DELETED) + yaffs_update_oh(in, NULL, 0, 0, 0, NULL); + + return YAFFS_OK; +} + +int yaffs_flush_file(struct yaffs_obj *in, int update_time, int data_sync) +{ + if (!in->dirty) + return YAFFS_OK; + + yaffs_flush_file_cache(in); + + if (data_sync) + return YAFFS_OK; + + if (update_time) + yaffs_load_current_time(in, 0, 0); + + return (yaffs_update_oh(in, NULL, 0, 0, 0, NULL) >= 0) ? + YAFFS_OK : YAFFS_FAIL; +} + + +/* yaffs_del_file deletes the whole file data + * and the inode associated with the file. + * It does not delete the links associated with the file. + */ +static int yaffs_unlink_file_if_needed(struct yaffs_obj *in) +{ + int ret_val; + int del_now = 0; + struct yaffs_dev *dev = in->my_dev; + + if (!in->my_inode) + del_now = 1; + + if (del_now) { + ret_val = + yaffs_change_obj_name(in, in->my_dev->del_dir, + _Y("deleted"), 0, 0); + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: immediate deletion of file %d", + in->obj_id); + in->deleted = 1; + in->my_dev->n_deleted_files++; + if (dev->param.disable_soft_del || dev->param.is_yaffs2) + yaffs_resize_file(in, 0); + yaffs_soft_del_file(in); + } else { + ret_val = + yaffs_change_obj_name(in, in->my_dev->unlinked_dir, + _Y("unlinked"), 0, 0); + } + return ret_val; +} + +static int yaffs_del_file(struct yaffs_obj *in) +{ + int ret_val = YAFFS_OK; + int deleted; /* Need to cache value on stack if in is freed */ + struct yaffs_dev *dev = in->my_dev; + + if (dev->param.disable_soft_del || dev->param.is_yaffs2) + yaffs_resize_file(in, 0); + + if (in->n_data_chunks > 0) { + /* Use soft deletion if there is data in the file. + * That won't be the case if it has been resized to zero. + */ + if (!in->unlinked) + ret_val = yaffs_unlink_file_if_needed(in); + + deleted = in->deleted; + + if (ret_val == YAFFS_OK && in->unlinked && !in->deleted) { + in->deleted = 1; + deleted = 1; + in->my_dev->n_deleted_files++; + yaffs_soft_del_file(in); + } + return deleted ? YAFFS_OK : YAFFS_FAIL; + } else { + /* The file has no data chunks so we toss it immediately */ + yaffs_free_tnode(in->my_dev, in->variant.file_variant.top); + in->variant.file_variant.top = NULL; + yaffs_generic_obj_del(in); + + return YAFFS_OK; + } +} + +int yaffs_is_non_empty_dir(struct yaffs_obj *obj) +{ + return (obj && + obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) && + !(list_empty(&obj->variant.dir_variant.children)); +} + +static int yaffs_del_dir(struct yaffs_obj *obj) +{ + /* First check that the directory is empty. */ + if (yaffs_is_non_empty_dir(obj)) + return YAFFS_FAIL; + + return yaffs_generic_obj_del(obj); +} + +static int yaffs_del_symlink(struct yaffs_obj *in) +{ + kfree(in->variant.symlink_variant.alias); + in->variant.symlink_variant.alias = NULL; + + return yaffs_generic_obj_del(in); +} + +static int yaffs_del_link(struct yaffs_obj *in) +{ + /* remove this hardlink from the list associated with the equivalent + * object + */ + list_del_init(&in->hard_links); + return yaffs_generic_obj_del(in); +} + +int yaffs_del_obj(struct yaffs_obj *obj) +{ + int ret_val = -1; + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + ret_val = yaffs_del_file(obj); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + if (!list_empty(&obj->variant.dir_variant.dirty)) { + yaffs_trace(YAFFS_TRACE_BACKGROUND, + "Remove object %d from dirty directories", + obj->obj_id); + list_del_init(&obj->variant.dir_variant.dirty); + } + return yaffs_del_dir(obj); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + ret_val = yaffs_del_symlink(obj); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + ret_val = yaffs_del_link(obj); + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + ret_val = yaffs_generic_obj_del(obj); + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + ret_val = 0; + break; /* should not happen. */ + } + return ret_val; +} + +static int yaffs_unlink_worker(struct yaffs_obj *obj) +{ + int del_now = 0; + + if (!obj) + return YAFFS_FAIL; + + if (!obj->my_inode) + del_now = 1; + + yaffs_update_parent(obj->parent); + + if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { + return yaffs_del_link(obj); + } else if (!list_empty(&obj->hard_links)) { + /* Curve ball: We're unlinking an object that has a hardlink. + * + * This problem arises because we are not strictly following + * The Linux link/inode model. + * + * We can't really delete the object. + * Instead, we do the following: + * - Select a hardlink. + * - Unhook it from the hard links + * - Move it from its parent directory so that the rename works. + * - Rename the object to the hardlink's name. + * - Delete the hardlink + */ + + struct yaffs_obj *hl; + struct yaffs_obj *parent; + int ret_val; + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + + hl = list_entry(obj->hard_links.next, struct yaffs_obj, + hard_links); + + yaffs_get_obj_name(hl, name, YAFFS_MAX_NAME_LENGTH + 1); + parent = hl->parent; + + list_del_init(&hl->hard_links); + + yaffs_add_obj_to_dir(obj->my_dev->unlinked_dir, hl); + + ret_val = yaffs_change_obj_name(obj, parent, name, 0, 0); + + if (ret_val == YAFFS_OK) + ret_val = yaffs_generic_obj_del(hl); + + return ret_val; + + } else if (del_now) { + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + return yaffs_del_file(obj); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + list_del_init(&obj->variant.dir_variant.dirty); + return yaffs_del_dir(obj); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + return yaffs_del_symlink(obj); + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + return yaffs_generic_obj_del(obj); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + case YAFFS_OBJECT_TYPE_UNKNOWN: + default: + return YAFFS_FAIL; + } + } else if (yaffs_is_non_empty_dir(obj)) { + return YAFFS_FAIL; + } else { + return yaffs_change_obj_name(obj, obj->my_dev->unlinked_dir, + _Y("unlinked"), 0, 0); + } +} + +static int yaffs_unlink_obj(struct yaffs_obj *obj) +{ + if (obj && obj->unlink_allowed) + return yaffs_unlink_worker(obj); + + return YAFFS_FAIL; +} + +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR *name) +{ + struct yaffs_obj *obj; + + obj = yaffs_find_by_name(dir, name); + return yaffs_unlink_obj(obj); +} + +/* Note: + * If old_name is NULL then we take old_dir as the object to be renamed. + */ +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR *old_name, + struct yaffs_obj *new_dir, const YCHAR *new_name) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *existing_target = NULL; + int force = 0; + int result; + struct yaffs_dev *dev; + + if (!old_dir || old_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + BUG(); + return YAFFS_FAIL; + } + if (!new_dir || new_dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + BUG(); + return YAFFS_FAIL; + } + + dev = old_dir->my_dev; + +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE + /* Special case for case insemsitive systems. + * While look-up is case insensitive, the name isn't. + * Therefore we might want to change x.txt to X.txt + */ + if (old_dir == new_dir && + old_name && new_name && + strcmp(old_name, new_name) == 0) + force = 1; +#endif + + if (strnlen(new_name, YAFFS_MAX_NAME_LENGTH + 1) > + YAFFS_MAX_NAME_LENGTH) + /* ENAMETOOLONG */ + return YAFFS_FAIL; + + if (old_name) + obj = yaffs_find_by_name(old_dir, old_name); + else{ + obj = old_dir; + old_dir = obj->parent; + } + + if (obj && obj->rename_allowed) { + /* Now handle an existing target, if there is one */ + existing_target = yaffs_find_by_name(new_dir, new_name); + if (yaffs_is_non_empty_dir(existing_target)) { + return YAFFS_FAIL; /* ENOTEMPTY */ + } else if (existing_target && existing_target != obj) { + /* Nuke the target first, using shadowing, + * but only if it isn't the same object. + * + * Note we must disable gc here otherwise it can mess + * up the shadowing. + * + */ + dev->gc_disable = 1; + yaffs_change_obj_name(obj, new_dir, new_name, force, + existing_target->obj_id); + existing_target->is_shadowed = 1; + yaffs_unlink_obj(existing_target); + dev->gc_disable = 0; + } + + result = yaffs_change_obj_name(obj, new_dir, new_name, 1, 0); + + yaffs_update_parent(old_dir); + if (new_dir != old_dir) + yaffs_update_parent(new_dir); + + return result; + } + return YAFFS_FAIL; +} + +/*----------------------- Initialisation Scanning ---------------------- */ + +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, + int backward_scanning) +{ + struct yaffs_obj *obj; + + if (backward_scanning) { + /* Handle YAFFS2 case (backward scanning) + * If the shadowed object exists then ignore. + */ + obj = yaffs_find_by_number(dev, obj_id); + if (obj) + return; + } + + /* Let's create it (if it does not exist) assuming it is a file so that + * it can do shrinking etc. + * We put it in unlinked dir to be cleaned up after the scanning + */ + obj = + yaffs_find_or_create_by_number(dev, obj_id, YAFFS_OBJECT_TYPE_FILE); + if (!obj) + return; + obj->is_shadowed = 1; + yaffs_add_obj_to_dir(dev->unlinked_dir, obj); + obj->variant.file_variant.shrink_size = 0; + obj->valid = 1; /* So that we don't read any other info. */ +} + +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list) +{ + struct list_head *lh; + struct list_head *save; + struct yaffs_obj *hl; + struct yaffs_obj *in; + + list_for_each_safe(lh, save, hard_list) { + hl = list_entry(lh, struct yaffs_obj, hard_links); + in = yaffs_find_by_number(dev, + hl->variant.hardlink_variant.equiv_id); + + if (in) { + /* Add the hardlink pointers */ + hl->variant.hardlink_variant.equiv_obj = in; + list_add(&hl->hard_links, &in->hard_links); + } else { + /* Todo Need to report/handle this better. + * Got a problem... hardlink to a non-existant object + */ + hl->variant.hardlink_variant.equiv_obj = NULL; + INIT_LIST_HEAD(&hl->hard_links); + } + } +} + +static void yaffs_strip_deleted_objs(struct yaffs_dev *dev) +{ + /* + * Sort out state of unlinked and deleted objects after scanning. + */ + struct list_head *i; + struct list_head *n; + struct yaffs_obj *l; + + if (dev->read_only) + return; + + /* Soft delete all the unlinked files */ + list_for_each_safe(i, n, + &dev->unlinked_dir->variant.dir_variant.children) { + l = list_entry(i, struct yaffs_obj, siblings); + yaffs_del_obj(l); + } + + list_for_each_safe(i, n, &dev->del_dir->variant.dir_variant.children) { + l = list_entry(i, struct yaffs_obj, siblings); + yaffs_del_obj(l); + } +} + +/* + * This code iterates through all the objects making sure that they are rooted. + * Any unrooted objects are re-rooted in lost+found. + * An object needs to be in one of: + * - Directly under deleted, unlinked + * - Directly or indirectly under root. + * + * Note: + * This code assumes that we don't ever change the current relationships + * between directories: + * root_dir->parent == unlinked_dir->parent == del_dir->parent == NULL + * lost-n-found->parent == root_dir + * + * This fixes the problem where directories might have inadvertently been + * deleted leaving the object "hanging" without being rooted in the + * directory tree. + */ + +static int yaffs_has_null_parent(struct yaffs_dev *dev, struct yaffs_obj *obj) +{ + return (obj == dev->del_dir || + obj == dev->unlinked_dir || obj == dev->root_dir); +} + +static void yaffs_fix_hanging_objs(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + struct yaffs_obj *parent; + int i; + struct list_head *lh; + struct list_head *n; + int depth_limit; + int hanging; + + if (dev->read_only) + return; + + /* Iterate through the objects in each hash entry, + * looking at each object. + * Make sure it is rooted. + */ + + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { + list_for_each_safe(lh, n, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link); + parent = obj->parent; + + if (yaffs_has_null_parent(dev, obj)) { + /* These directories are not hanging */ + hanging = 0; + } else if (!parent || + parent->variant_type != + YAFFS_OBJECT_TYPE_DIRECTORY) { + hanging = 1; + } else if (yaffs_has_null_parent(dev, parent)) { + hanging = 0; + } else { + /* + * Need to follow the parent chain to + * see if it is hanging. + */ + hanging = 0; + depth_limit = 100; + + while (parent != dev->root_dir && + parent->parent && + parent->parent->variant_type == + YAFFS_OBJECT_TYPE_DIRECTORY && + depth_limit > 0) { + parent = parent->parent; + depth_limit--; + } + if (parent != dev->root_dir) + hanging = 1; + } + if (hanging) { + yaffs_trace(YAFFS_TRACE_SCAN, + "Hanging object %d moved to lost and found", + obj->obj_id); + yaffs_add_obj_to_dir(dev->lost_n_found, obj); + } + } + } +} + +/* + * Delete directory contents for cleaning up lost and found. + */ +static void yaffs_del_dir_contents(struct yaffs_obj *dir) +{ + struct yaffs_obj *obj; + struct list_head *lh; + struct list_head *n; + + if (dir->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + BUG(); + + list_for_each_safe(lh, n, &dir->variant.dir_variant.children) { + obj = list_entry(lh, struct yaffs_obj, siblings); + if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) + yaffs_del_dir_contents(obj); + yaffs_trace(YAFFS_TRACE_SCAN, + "Deleting lost_found object %d", + obj->obj_id); + yaffs_unlink_obj(obj); + } +} + +static void yaffs_empty_l_n_f(struct yaffs_dev *dev) +{ + yaffs_del_dir_contents(dev->lost_n_found); +} + + +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *directory, + const YCHAR *name) +{ + int sum; + struct list_head *i; + YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1]; + struct yaffs_obj *l; + + if (!name) + return NULL; + + if (!directory) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: yaffs_find_by_name: null pointer directory" + ); + BUG(); + return NULL; + } + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "tragedy: yaffs_find_by_name: non-directory" + ); + BUG(); + } + + sum = yaffs_calc_name_sum(name); + + list_for_each(i, &directory->variant.dir_variant.children) { + l = list_entry(i, struct yaffs_obj, siblings); + + if (l->parent != directory) + BUG(); + + yaffs_check_obj_details_loaded(l); + + /* Special case for lost-n-found */ + if (l->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { + if (!strcmp(name, YAFFS_LOSTNFOUND_NAME)) + return l; + } else if (l->sum == sum || l->hdr_chunk <= 0) { + /* LostnFound chunk called Objxxx + * Do a real check + */ + yaffs_get_obj_name(l, buffer, + YAFFS_MAX_NAME_LENGTH + 1); + if (!strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH)) + return l; + } + } + return NULL; +} + +/* GetEquivalentObject dereferences any hard links to get to the + * actual object. + */ + +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj) +{ + if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) { + obj = obj->variant.hardlink_variant.equiv_obj; + yaffs_check_obj_details_loaded(obj); + } + return obj; +} + +/* + * A note or two on object names. + * * If the object name is missing, we then make one up in the form objnnn + * + * * ASCII names are stored in the object header's name field from byte zero + * * Unicode names are historically stored starting from byte zero. + * + * Then there are automatic Unicode names... + * The purpose of these is to save names in a way that can be read as + * ASCII or Unicode names as appropriate, thus allowing a Unicode and ASCII + * system to share files. + * + * These automatic unicode are stored slightly differently... + * - If the name can fit in the ASCII character space then they are saved as + * ascii names as per above. + * - If the name needs Unicode then the name is saved in Unicode + * starting at oh->name[1]. + + */ +static void yaffs_fix_null_name(struct yaffs_obj *obj, YCHAR *name, + int buffer_size) +{ + /* Create an object name if we could not find one. */ + if (strnlen(name, YAFFS_MAX_NAME_LENGTH) == 0) { + YCHAR local_name[20]; + YCHAR num_string[20]; + YCHAR *x = &num_string[19]; + unsigned v = obj->obj_id; + num_string[19] = 0; + while (v > 0) { + x--; + *x = '0' + (v % 10); + v /= 10; + } + /* make up a name */ + strcpy(local_name, YAFFS_LOSTNFOUND_PREFIX); + strcat(local_name, x); + strncpy(name, local_name, buffer_size - 1); + } +} + +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR *name, int buffer_size) +{ + memset(name, 0, buffer_size * sizeof(YCHAR)); + yaffs_check_obj_details_loaded(obj); + if (obj->obj_id == YAFFS_OBJECTID_LOSTNFOUND) { + strncpy(name, YAFFS_LOSTNFOUND_NAME, buffer_size - 1); + } else if (obj->short_name[0]) { + strcpy(name, obj->short_name); + } else if (obj->hdr_chunk > 0) { + int result; + u8 *buffer = yaffs_get_temp_buffer(obj->my_dev); + + struct yaffs_obj_hdr *oh = (struct yaffs_obj_hdr *)buffer; + + memset(buffer, 0, obj->my_dev->data_bytes_per_chunk); + + if (obj->hdr_chunk > 0) { + result = yaffs_rd_chunk_tags_nand(obj->my_dev, + obj->hdr_chunk, + buffer, NULL); + } + yaffs_load_name_from_oh(obj->my_dev, name, oh->name, + buffer_size); + + yaffs_release_temp_buffer(obj->my_dev, buffer); + } + + yaffs_fix_null_name(obj, name, buffer_size); + + return strnlen(name, YAFFS_MAX_NAME_LENGTH); +} + +loff_t yaffs_get_obj_length(struct yaffs_obj *obj) +{ + /* Dereference any hard linking */ + obj = yaffs_get_equivalent_obj(obj); + + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + return obj->variant.file_variant.file_size; + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { + if (!obj->variant.symlink_variant.alias) + return 0; + return strnlen(obj->variant.symlink_variant.alias, + YAFFS_MAX_ALIAS_LENGTH); + } else { + /* Only a directory should drop through to here */ + return obj->my_dev->data_bytes_per_chunk; + } +} + +int yaffs_get_obj_link_count(struct yaffs_obj *obj) +{ + int count = 0; + struct list_head *i; + + if (!obj->unlinked) + count++; /* the object itself */ + + list_for_each(i, &obj->hard_links) + count++; /* add the hard links; */ + + return count; +} + +int yaffs_get_obj_inode(struct yaffs_obj *obj) +{ + obj = yaffs_get_equivalent_obj(obj); + + return obj->obj_id; +} + +unsigned yaffs_get_obj_type(struct yaffs_obj *obj) +{ + obj = yaffs_get_equivalent_obj(obj); + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + return DT_REG; + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + return DT_DIR; + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + return DT_LNK; + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + return DT_REG; + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + if (S_ISFIFO(obj->yst_mode)) + return DT_FIFO; + if (S_ISCHR(obj->yst_mode)) + return DT_CHR; + if (S_ISBLK(obj->yst_mode)) + return DT_BLK; + if (S_ISSOCK(obj->yst_mode)) + return DT_SOCK; + return DT_REG; + break; + default: + return DT_REG; + break; + } +} + +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj) +{ + obj = yaffs_get_equivalent_obj(obj); + if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) + return yaffs_clone_str(obj->variant.symlink_variant.alias); + else + return yaffs_clone_str(_Y("")); +} + +/*--------------------------- Initialisation code -------------------------- */ + +static int yaffs_check_dev_fns(const struct yaffs_dev *dev) +{ + /* Common functions, gotta have */ + if (!dev->param.erase_fn || !dev->param.initialise_flash_fn) + return 0; + + /* Can use the "with tags" style interface for yaffs1 or yaffs2 */ + if (dev->param.write_chunk_tags_fn && + dev->param.read_chunk_tags_fn && + !dev->param.write_chunk_fn && + !dev->param.read_chunk_fn && + dev->param.bad_block_fn && dev->param.query_block_fn) + return 1; + + /* Can use the "spare" style interface for yaffs1 */ + if (!dev->param.is_yaffs2 && + !dev->param.write_chunk_tags_fn && + !dev->param.read_chunk_tags_fn && + dev->param.write_chunk_fn && + dev->param.read_chunk_fn && + !dev->param.bad_block_fn && !dev->param.query_block_fn) + return 1; + + return 0; /* bad */ +} + +static int yaffs_create_initial_dir(struct yaffs_dev *dev) +{ + /* Initialise the unlinked, deleted, root and lost+found directories */ + dev->lost_n_found = dev->root_dir = NULL; + dev->unlinked_dir = dev->del_dir = NULL; + dev->unlinked_dir = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR); + dev->del_dir = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_DELETED, S_IFDIR); + dev->root_dir = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_ROOT, + YAFFS_ROOT_MODE | S_IFDIR); + dev->lost_n_found = + yaffs_create_fake_dir(dev, YAFFS_OBJECTID_LOSTNFOUND, + YAFFS_LOSTNFOUND_MODE | S_IFDIR); + + if (dev->lost_n_found && dev->root_dir && dev->unlinked_dir + && dev->del_dir) { + yaffs_add_obj_to_dir(dev->root_dir, dev->lost_n_found); + return YAFFS_OK; + } + return YAFFS_FAIL; +} + +int yaffs_guts_initialise(struct yaffs_dev *dev) +{ + int init_failed = 0; + unsigned x; + int bits; + + yaffs_trace(YAFFS_TRACE_TRACING, "yaffs: yaffs_guts_initialise()"); + + /* Check stuff that must be set */ + + if (!dev) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs: Need a device" + ); + return YAFFS_FAIL; + } + + if (dev->is_mounted) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "device already mounted"); + return YAFFS_FAIL; + } + + dev->internal_start_block = dev->param.start_block; + dev->internal_end_block = dev->param.end_block; + dev->block_offset = 0; + dev->chunk_offset = 0; + dev->n_free_chunks = 0; + + dev->gc_block = 0; + + if (dev->param.start_block == 0) { + dev->internal_start_block = dev->param.start_block + 1; + dev->internal_end_block = dev->param.end_block + 1; + dev->block_offset = 1; + dev->chunk_offset = dev->param.chunks_per_block; + } + + /* Check geometry parameters. */ + + if ((!dev->param.inband_tags && dev->param.is_yaffs2 && + dev->param.total_bytes_per_chunk < 1024) || + (!dev->param.is_yaffs2 && + dev->param.total_bytes_per_chunk < 512) || + (dev->param.inband_tags && !dev->param.is_yaffs2) || + dev->param.chunks_per_block < 2 || + dev->param.n_reserved_blocks < 2 || + dev->internal_start_block <= 0 || + dev->internal_end_block <= 0 || + dev->internal_end_block <= + (dev->internal_start_block + dev->param.n_reserved_blocks + 2) + ) { + /* otherwise it is too small */ + yaffs_trace(YAFFS_TRACE_ALWAYS, + "NAND geometry problems: chunk size %d, type is yaffs%s, inband_tags %d ", + dev->param.total_bytes_per_chunk, + dev->param.is_yaffs2 ? "2" : "", + dev->param.inband_tags); + return YAFFS_FAIL; + } + + if (yaffs_init_nand(dev) != YAFFS_OK) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "InitialiseNAND failed"); + return YAFFS_FAIL; + } + + /* Sort out space for inband tags, if required */ + if (dev->param.inband_tags) + dev->data_bytes_per_chunk = + dev->param.total_bytes_per_chunk - + sizeof(struct yaffs_packed_tags2_tags_only); + else + dev->data_bytes_per_chunk = dev->param.total_bytes_per_chunk; + + /* Got the right mix of functions? */ + if (!yaffs_check_dev_fns(dev)) { + /* Function missing */ + yaffs_trace(YAFFS_TRACE_ALWAYS, + "device function(s) missing or wrong"); + + return YAFFS_FAIL; + } + + /* Finished with most checks. Further checks happen later on too. */ + + dev->is_mounted = 1; + + /* OK now calculate a few things for the device */ + + /* + * Calculate all the chunk size manipulation numbers: + */ + x = dev->data_bytes_per_chunk; + /* We always use dev->chunk_shift and dev->chunk_div */ + dev->chunk_shift = calc_shifts(x); + x >>= dev->chunk_shift; + dev->chunk_div = x; + /* We only use chunk mask if chunk_div is 1 */ + dev->chunk_mask = (1 << dev->chunk_shift) - 1; + + /* + * Calculate chunk_grp_bits. + * We need to find the next power of 2 > than internal_end_block + */ + + x = dev->param.chunks_per_block * (dev->internal_end_block + 1); + + bits = calc_shifts_ceiling(x); + + /* Set up tnode width if wide tnodes are enabled. */ + if (!dev->param.wide_tnodes_disabled) { + /* bits must be even so that we end up with 32-bit words */ + if (bits & 1) + bits++; + if (bits < 16) + dev->tnode_width = 16; + else + dev->tnode_width = bits; + } else { + dev->tnode_width = 16; + } + + dev->tnode_mask = (1 << dev->tnode_width) - 1; + + /* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled), + * so if the bitwidth of the + * chunk range we're using is greater than 16 we need + * to figure out chunk shift and chunk_grp_size + */ + + if (bits <= dev->tnode_width) + dev->chunk_grp_bits = 0; + else + dev->chunk_grp_bits = bits - dev->tnode_width; + + dev->tnode_size = (dev->tnode_width * YAFFS_NTNODES_LEVEL0) / 8; + if (dev->tnode_size < sizeof(struct yaffs_tnode)) + dev->tnode_size = sizeof(struct yaffs_tnode); + + dev->chunk_grp_size = 1 << dev->chunk_grp_bits; + + if (dev->param.chunks_per_block < dev->chunk_grp_size) { + /* We have a problem because the soft delete won't work if + * the chunk group size > chunks per block. + * This can be remedied by using larger "virtual blocks". + */ + yaffs_trace(YAFFS_TRACE_ALWAYS, "chunk group too large"); + + return YAFFS_FAIL; + } + + /* Finished verifying the device, continue with initialisation */ + + /* More device initialisation */ + dev->all_gcs = 0; + dev->passive_gc_count = 0; + dev->oldest_dirty_gc_count = 0; + dev->bg_gcs = 0; + dev->gc_block_finder = 0; + dev->buffered_block = -1; + dev->doing_buffered_block_rewrite = 0; + dev->n_deleted_files = 0; + dev->n_bg_deletions = 0; + dev->n_unlinked_files = 0; + dev->n_ecc_fixed = 0; + dev->n_ecc_unfixed = 0; + dev->n_tags_ecc_fixed = 0; + dev->n_tags_ecc_unfixed = 0; + dev->n_erase_failures = 0; + dev->n_erased_blocks = 0; + dev->gc_disable = 0; + dev->has_pending_prioritised_gc = 1; + /* Assume the worst for now, will get fixed on first GC */ + INIT_LIST_HEAD(&dev->dirty_dirs); + dev->oldest_dirty_seq = 0; + dev->oldest_dirty_block = 0; + + /* Initialise temporary buffers and caches. */ + if (!yaffs_init_tmp_buffers(dev)) + init_failed = 1; + + dev->cache = NULL; + dev->gc_cleanup_list = NULL; + + if (!init_failed && dev->param.n_caches > 0) { + int i; + void *buf; + int cache_bytes = + dev->param.n_caches * sizeof(struct yaffs_cache); + + if (dev->param.n_caches > YAFFS_MAX_SHORT_OP_CACHES) + dev->param.n_caches = YAFFS_MAX_SHORT_OP_CACHES; + + dev->cache = kmalloc(cache_bytes, GFP_NOFS); + + buf = (u8 *) dev->cache; + + if (dev->cache) + memset(dev->cache, 0, cache_bytes); + + for (i = 0; i < dev->param.n_caches && buf; i++) { + dev->cache[i].object = NULL; + dev->cache[i].last_use = 0; + dev->cache[i].dirty = 0; + dev->cache[i].data = buf = + kmalloc(dev->param.total_bytes_per_chunk, GFP_NOFS); + } + if (!buf) + init_failed = 1; + + dev->cache_last_use = 0; + } + + dev->cache_hits = 0; + + if (!init_failed) { + dev->gc_cleanup_list = + kmalloc(dev->param.chunks_per_block * sizeof(u32), + GFP_NOFS); + if (!dev->gc_cleanup_list) + init_failed = 1; + } + + if (dev->param.is_yaffs2) + dev->param.use_header_file_size = 1; + + if (!init_failed && !yaffs_init_blocks(dev)) + init_failed = 1; + + yaffs_init_tnodes_and_objs(dev); + + if (!init_failed && !yaffs_create_initial_dir(dev)) + init_failed = 1; + + if (!init_failed && dev->param.is_yaffs2 && + !dev->param.disable_summary && + !yaffs_summary_init(dev)) + init_failed = 1; + + if (!init_failed) { + /* Now scan the flash. */ + if (dev->param.is_yaffs2) { + if (yaffs2_checkpt_restore(dev)) { + yaffs_check_obj_details_loaded(dev->root_dir); + yaffs_trace(YAFFS_TRACE_CHECKPOINT | + YAFFS_TRACE_MOUNT, + "yaffs: restored from checkpoint" + ); + } else { + + /* Clean up the mess caused by an aborted + * checkpoint load then scan backwards. + */ + yaffs_deinit_blocks(dev); + + yaffs_deinit_tnodes_and_objs(dev); + + dev->n_erased_blocks = 0; + dev->n_free_chunks = 0; + dev->alloc_block = -1; + dev->alloc_page = -1; + dev->n_deleted_files = 0; + dev->n_unlinked_files = 0; + dev->n_bg_deletions = 0; + + if (!init_failed && !yaffs_init_blocks(dev)) + init_failed = 1; + + yaffs_init_tnodes_and_objs(dev); + + if (!init_failed + && !yaffs_create_initial_dir(dev)) + init_failed = 1; + + if (!init_failed && !yaffs2_scan_backwards(dev)) + init_failed = 1; + } + } else if (!yaffs1_scan(dev)) { + init_failed = 1; + } + + yaffs_strip_deleted_objs(dev); + yaffs_fix_hanging_objs(dev); + if (dev->param.empty_lost_n_found) + yaffs_empty_l_n_f(dev); + } + + if (init_failed) { + /* Clean up the mess */ + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: yaffs_guts_initialise() aborted."); + + yaffs_deinitialise(dev); + return YAFFS_FAIL; + } + + /* Zero out stats */ + dev->n_page_reads = 0; + dev->n_page_writes = 0; + dev->n_erasures = 0; + dev->n_gc_copies = 0; + dev->n_retried_writes = 0; + + dev->n_retired_blocks = 0; + + yaffs_verify_free_chunks(dev); + yaffs_verify_blocks(dev); + + /* Clean up any aborted checkpoint data */ + if (!dev->is_checkpointed && dev->blocks_in_checkpt > 0) + yaffs2_checkpt_invalidate(dev); + + yaffs_trace(YAFFS_TRACE_TRACING, + "yaffs: yaffs_guts_initialise() done."); + return YAFFS_OK; +} + +void yaffs_deinitialise(struct yaffs_dev *dev) +{ + if (dev->is_mounted) { + int i; + + yaffs_deinit_blocks(dev); + yaffs_deinit_tnodes_and_objs(dev); + yaffs_summary_deinit(dev); + + if (dev->param.n_caches > 0 && dev->cache) { + + for (i = 0; i < dev->param.n_caches; i++) { + kfree(dev->cache[i].data); + dev->cache[i].data = NULL; + } + + kfree(dev->cache); + dev->cache = NULL; + } + + kfree(dev->gc_cleanup_list); + + for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) + kfree(dev->temp_buffer[i].buffer); + + dev->is_mounted = 0; + + if (dev->param.deinitialise_flash_fn) + dev->param.deinitialise_flash_fn(dev); + } +} + +int yaffs_count_free_chunks(struct yaffs_dev *dev) +{ + int n_free = 0; + int b; + struct yaffs_block_info *blk; + + blk = dev->block_info; + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { + switch (blk->block_state) { + case YAFFS_BLOCK_STATE_EMPTY: + case YAFFS_BLOCK_STATE_ALLOCATING: + case YAFFS_BLOCK_STATE_COLLECTING: + case YAFFS_BLOCK_STATE_FULL: + n_free += + (dev->param.chunks_per_block - blk->pages_in_use + + blk->soft_del_pages); + break; + default: + break; + } + blk++; + } + return n_free; +} + +int yaffs_get_n_free_chunks(struct yaffs_dev *dev) +{ + /* This is what we report to the outside world */ + int n_free; + int n_dirty_caches; + int blocks_for_checkpt; + int i; + + n_free = dev->n_free_chunks; + n_free += dev->n_deleted_files; + + /* Now count and subtract the number of dirty chunks in the cache. */ + + for (n_dirty_caches = 0, i = 0; i < dev->param.n_caches; i++) { + if (dev->cache[i].dirty) + n_dirty_caches++; + } + + n_free -= n_dirty_caches; + + n_free -= + ((dev->param.n_reserved_blocks + 1) * dev->param.chunks_per_block); + + /* Now figure checkpoint space and report that... */ + blocks_for_checkpt = yaffs_calc_checkpt_blocks_required(dev); + + n_free -= (blocks_for_checkpt * dev->param.chunks_per_block); + + if (n_free < 0) + n_free = 0; + + return n_free; +} + + +int yaffs_format_dev(struct yaffs_dev *dev) +{ + int i; + enum yaffs_block_state state; + u32 dummy; + + if(dev->is_mounted) + return YAFFS_FAIL; + + /* + * The runtime variables might not have been set up, + * so set up what we need. + */ + dev->internal_start_block = dev->param.start_block; + dev->internal_end_block = dev->param.end_block; + dev->block_offset = 0; + dev->chunk_offset = 0; + + if (dev->param.start_block == 0) { + dev->internal_start_block = dev->param.start_block + 1; + dev->internal_end_block = dev->param.end_block + 1; + dev->block_offset = 1; + dev->chunk_offset = dev->param.chunks_per_block; + } + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + yaffs_query_init_block_state(dev, i, &state, &dummy); + if (state != YAFFS_BLOCK_STATE_DEAD) + yaffs_erase_block(dev, i); + } + + return YAFFS_OK; +} + + +/* + * Marshalling functions to get loff_t file sizes into and out of + * object headers. + */ +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize) +{ + oh->file_size_low = (fsize & 0xFFFFFFFF); + oh->file_size_high = ((fsize >> 32) & 0xFFFFFFFF); +} + +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh) +{ + loff_t retval; + + if (sizeof(loff_t) >= 8 && ~(oh->file_size_high)) + retval = (((loff_t) oh->file_size_high) << 32) | + (((loff_t) oh->file_size_low) & 0xFFFFFFFF); + else + retval = (loff_t) oh->file_size_low; + + return retval; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h new file mode 100644 index 0000000..0e334bd --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_guts.h @@ -0,0 +1,977 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_GUTS_H__ +#define __YAFFS_GUTS_H__ + +#include "yportenv.h" + +#define YAFFS_OK 1 +#define YAFFS_FAIL 0 + +/* Give us a Y=0x59, + * Give us an A=0x41, + * Give us an FF=0xff + * Give us an S=0x53 + * And what have we got... + */ +#define YAFFS_MAGIC 0x5941ff53 + +/* + * Tnodes form a tree with the tnodes in "levels" + * Levels greater than 0 hold 8 slots which point to other tnodes. + * Those at level 0 hold 16 slots which point to chunks in NAND. + * + * A maximum level of 8 thust supports files of size up to: + * + * 2^(3*MAX_LEVEL+4) + * + * Thus a max level of 8 supports files with up to 2^^28 chunks which gives + * a maximum file size of arounf 51Gbytees with 2k chunks. + */ +#define YAFFS_NTNODES_LEVEL0 16 +#define YAFFS_TNODES_LEVEL0_BITS 4 +#define YAFFS_TNODES_LEVEL0_MASK 0xf + +#define YAFFS_NTNODES_INTERNAL (YAFFS_NTNODES_LEVEL0 / 2) +#define YAFFS_TNODES_INTERNAL_BITS (YAFFS_TNODES_LEVEL0_BITS - 1) +#define YAFFS_TNODES_INTERNAL_MASK 0x7 +#define YAFFS_TNODES_MAX_LEVEL 8 +#define YAFFS_TNODES_MAX_BITS (YAFFS_TNODES_LEVEL0_BITS + \ + YAFFS_TNODES_INTERNAL_BITS * \ + YAFFS_TNODES_MAX_LEVEL) +#define YAFFS_MAX_CHUNK_ID ((1 << YAFFS_TNODES_MAX_BITS) - 1) + +#define YAFFS_MAX_FILE_SIZE_32 0x7fffffff + +/* Constants for YAFFS1 mode */ +#define YAFFS_BYTES_PER_SPARE 16 +#define YAFFS_BYTES_PER_CHUNK 512 +#define YAFFS_CHUNK_SIZE_SHIFT 9 +#define YAFFS_CHUNKS_PER_BLOCK 32 +#define YAFFS_BYTES_PER_BLOCK (YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK) + +#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 1024 +#define YAFFS_MIN_YAFFS2_SPARE_SIZE 32 + + + +#define YAFFS_ALLOCATION_NOBJECTS 100 +#define YAFFS_ALLOCATION_NTNODES 100 +#define YAFFS_ALLOCATION_NLINKS 100 + +#define YAFFS_NOBJECT_BUCKETS 256 + +#define YAFFS_OBJECT_SPACE 0x40000 +#define YAFFS_MAX_OBJECT_ID (YAFFS_OBJECT_SPACE - 1) + +/* Binary data version stamps */ +#define YAFFS_SUMMARY_VERSION 1 +#define YAFFS_CHECKPOINT_VERSION 7 + +#ifdef CONFIG_YAFFS_UNICODE +#define YAFFS_MAX_NAME_LENGTH 127 +#define YAFFS_MAX_ALIAS_LENGTH 79 +#else +#define YAFFS_MAX_NAME_LENGTH 255 +#define YAFFS_MAX_ALIAS_LENGTH 159 +#endif + +#define YAFFS_SHORT_NAME_LENGTH 15 + +/* Some special object ids for pseudo objects */ +#define YAFFS_OBJECTID_ROOT 1 +#define YAFFS_OBJECTID_LOSTNFOUND 2 +#define YAFFS_OBJECTID_UNLINKED 3 +#define YAFFS_OBJECTID_DELETED 4 + +/* Fake object Id for summary data */ +#define YAFFS_OBJECTID_SUMMARY 0x10 + +/* Pseudo object ids for checkpointing */ +#define YAFFS_OBJECTID_CHECKPOINT_DATA 0x20 +#define YAFFS_SEQUENCE_CHECKPOINT_DATA 0x21 + +#define YAFFS_MAX_SHORT_OP_CACHES 20 + +#define YAFFS_N_TEMP_BUFFERS 6 + +/* We limit the number attempts at sucessfully saving a chunk of data. + * Small-page devices have 32 pages per block; large-page devices have 64. + * Default to something in the order of 5 to 10 blocks worth of chunks. + */ +#define YAFFS_WR_ATTEMPTS (5*64) + +/* Sequence numbers are used in YAFFS2 to determine block allocation order. + * The range is limited slightly to help distinguish bad numbers from good. + * This also allows us to perhaps in the future use special numbers for + * special purposes. + * EFFFFF00 allows the allocation of 8 blocks/second (~1Mbytes) for 15 years, + * and is a larger number than the lifetime of a 2GB device. + */ +#define YAFFS_LOWEST_SEQUENCE_NUMBER 0x00001000 +#define YAFFS_HIGHEST_SEQUENCE_NUMBER 0xefffff00 + +/* Special sequence number for bad block that failed to be marked bad */ +#define YAFFS_SEQUENCE_BAD_BLOCK 0xffff0000 + +/* ChunkCache is used for short read/write operations.*/ +struct yaffs_cache { + struct yaffs_obj *object; + int chunk_id; + int last_use; + int dirty; + int n_bytes; /* Only valid if the cache is dirty */ + int locked; /* Can't push out or flush while locked. */ + u8 *data; +}; + +/* yaffs1 tags structures in RAM + * NB This uses bitfield. Bitfields should not straddle a u32 boundary + * otherwise the structure size will get blown out. + */ + +struct yaffs_tags { + unsigned chunk_id:20; + unsigned serial_number:2; + unsigned n_bytes_lsb:10; + unsigned obj_id:18; + unsigned ecc:12; + unsigned n_bytes_msb:2; +}; + +union yaffs_tags_union { + struct yaffs_tags as_tags; + u8 as_bytes[8]; +}; + + +/* Stuff used for extended tags in YAFFS2 */ + +enum yaffs_ecc_result { + YAFFS_ECC_RESULT_UNKNOWN, + YAFFS_ECC_RESULT_NO_ERROR, + YAFFS_ECC_RESULT_FIXED, + YAFFS_ECC_RESULT_UNFIXED +}; + +enum yaffs_obj_type { + YAFFS_OBJECT_TYPE_UNKNOWN, + YAFFS_OBJECT_TYPE_FILE, + YAFFS_OBJECT_TYPE_SYMLINK, + YAFFS_OBJECT_TYPE_DIRECTORY, + YAFFS_OBJECT_TYPE_HARDLINK, + YAFFS_OBJECT_TYPE_SPECIAL +}; + +#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL + +struct yaffs_ext_tags { + unsigned chunk_used; /* Status of the chunk: used or unused */ + unsigned obj_id; /* If 0 this is not used */ + unsigned chunk_id; /* If 0 this is a header, else a data chunk */ + unsigned n_bytes; /* Only valid for data chunks */ + + /* The following stuff only has meaning when we read */ + enum yaffs_ecc_result ecc_result; + unsigned block_bad; + + /* YAFFS 1 stuff */ + unsigned is_deleted; /* The chunk is marked deleted */ + unsigned serial_number; /* Yaffs1 2-bit serial number */ + + /* YAFFS2 stuff */ + unsigned seq_number; /* The sequence number of this block */ + + /* Extra info if this is an object header (YAFFS2 only) */ + + unsigned extra_available; /* Extra info available if not zero */ + unsigned extra_parent_id; /* The parent object */ + unsigned extra_is_shrink; /* Is it a shrink header? */ + unsigned extra_shadows; /* Does this shadow another object? */ + + enum yaffs_obj_type extra_obj_type; /* What object type? */ + + loff_t extra_file_size; /* Length if it is a file */ + unsigned extra_equiv_id; /* Equivalent object for a hard link */ +}; + +/* Spare structure for YAFFS1 */ +struct yaffs_spare { + u8 tb0; + u8 tb1; + u8 tb2; + u8 tb3; + u8 page_status; /* set to 0 to delete the chunk */ + u8 block_status; + u8 tb4; + u8 tb5; + u8 ecc1[3]; + u8 tb6; + u8 tb7; + u8 ecc2[3]; +}; + +/*Special structure for passing through to mtd */ +struct yaffs_nand_spare { + struct yaffs_spare spare; + int eccres1; + int eccres2; +}; + +/* Block data in RAM */ + +enum yaffs_block_state { + YAFFS_BLOCK_STATE_UNKNOWN = 0, + + YAFFS_BLOCK_STATE_SCANNING, + /* Being scanned */ + + YAFFS_BLOCK_STATE_NEEDS_SCAN, + /* The block might have something on it (ie it is allocating or full, + * perhaps empty) but it needs to be scanned to determine its true + * state. + * This state is only valid during scanning. + * NB We tolerate empty because the pre-scanner might be incapable of + * deciding + * However, if this state is returned on a YAFFS2 device, + * then we expect a sequence number + */ + + YAFFS_BLOCK_STATE_EMPTY, + /* This block is empty */ + + YAFFS_BLOCK_STATE_ALLOCATING, + /* This block is partially allocated. + * At least one page holds valid data. + * This is the one currently being used for page + * allocation. Should never be more than one of these. + * If a block is only partially allocated at mount it is treated as + * full. + */ + + YAFFS_BLOCK_STATE_FULL, + /* All the pages in this block have been allocated. + * If a block was only partially allocated when mounted we treat + * it as fully allocated. + */ + + YAFFS_BLOCK_STATE_DIRTY, + /* The block was full and now all chunks have been deleted. + * Erase me, reuse me. + */ + + YAFFS_BLOCK_STATE_CHECKPOINT, + /* This block is assigned to holding checkpoint data. */ + + YAFFS_BLOCK_STATE_COLLECTING, + /* This block is being garbage collected */ + + YAFFS_BLOCK_STATE_DEAD + /* This block has failed and is not in use */ +}; + +#define YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1) + +struct yaffs_block_info { + + int soft_del_pages:10; /* number of soft deleted pages */ + int pages_in_use:10; /* number of pages in use */ + unsigned block_state:4; /* One of the above block states. */ + /* NB use unsigned because enum is sometimes + * an int */ + u32 needs_retiring:1; /* Data has failed on this block, */ + /*need to get valid data off and retire*/ + u32 skip_erased_check:1;/* Skip the erased check on this block */ + u32 gc_prioritise:1; /* An ECC check or blank check has failed. + Block should be prioritised for GC */ + u32 chunk_error_strikes:3; /* How many times we've had ecc etc + failures on this block and tried to reuse it */ + u32 has_summary:1; /* The block has a summary */ + + u32 has_shrink_hdr:1; /* This block has at least one shrink header */ + u32 seq_number; /* block sequence number for yaffs2 */ + +}; + +/* -------------------------- Object structure -------------------------------*/ +/* This is the object structure as stored on NAND */ + +struct yaffs_obj_hdr { + enum yaffs_obj_type type; + + /* Apply to everything */ + int parent_obj_id; + u16 sum_no_longer_used; /* checksum of name. No longer used */ + YCHAR name[YAFFS_MAX_NAME_LENGTH + 1]; + + /* The following apply to all object types except for hard links */ + u32 yst_mode; /* protection */ + + u32 yst_uid; + u32 yst_gid; + u32 yst_atime; + u32 yst_mtime; + u32 yst_ctime; + + /* File size applies to files only */ + u32 file_size_low; + + /* Equivalent object id applies to hard links only. */ + int equiv_id; + + /* Alias is for symlinks only. */ + YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1]; + + u32 yst_rdev; /* stuff for block and char devices (major/min) */ + + u32 win_ctime[2]; + u32 win_atime[2]; + u32 win_mtime[2]; + + u32 inband_shadowed_obj_id; + u32 inband_is_shrink; + + u32 file_size_high; + u32 reserved[1]; + int shadows_obj; /* This object header shadows the + specified object if > 0 */ + + /* is_shrink applies to object headers written when wemake a hole. */ + u32 is_shrink; + +}; + +/*--------------------------- Tnode -------------------------- */ + +struct yaffs_tnode { + struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL]; +}; + +/*------------------------ Object -----------------------------*/ +/* An object can be one of: + * - a directory (no data, has children links + * - a regular file (data.... not prunes :->). + * - a symlink [symbolic link] (the alias). + * - a hard link + */ + +struct yaffs_file_var { + loff_t file_size; + loff_t scanned_size; + loff_t shrink_size; + int top_level; + struct yaffs_tnode *top; +}; + +struct yaffs_dir_var { + struct list_head children; /* list of child links */ + struct list_head dirty; /* Entry for list of dirty directories */ +}; + +struct yaffs_symlink_var { + YCHAR *alias; +}; + +struct yaffs_hardlink_var { + struct yaffs_obj *equiv_obj; + u32 equiv_id; +}; + +union yaffs_obj_var { + struct yaffs_file_var file_variant; + struct yaffs_dir_var dir_variant; + struct yaffs_symlink_var symlink_variant; + struct yaffs_hardlink_var hardlink_variant; +}; + +struct yaffs_obj { + u8 deleted:1; /* This should only apply to unlinked files. */ + u8 soft_del:1; /* it has also been soft deleted */ + u8 unlinked:1; /* An unlinked file.*/ + u8 fake:1; /* A fake object has no presence on NAND. */ + u8 rename_allowed:1; /* Some objects cannot be renamed. */ + u8 unlink_allowed:1; + u8 dirty:1; /* the object needs to be written to flash */ + u8 valid:1; /* When the file system is being loaded up, this + * object might be created before the data + * is available + * ie. file data chunks encountered before + * the header. + */ + u8 lazy_loaded:1; /* This object has been lazy loaded and + * is missing some detail */ + + u8 defered_free:1; /* Object is removed from NAND, but is + * still in the inode cache. + * Free of object is defered. + * until the inode is released. + */ + u8 being_created:1; /* This object is still being created + * so skip some verification checks. */ + u8 is_shadowed:1; /* This object is shadowed on the way + * to being renamed. */ + + u8 xattr_known:1; /* We know if this has object has xattribs + * or not. */ + u8 has_xattr:1; /* This object has xattribs. + * Only valid if xattr_known. */ + + u8 serial; /* serial number of chunk in NAND.*/ + u16 sum; /* sum of the name to speed searching */ + + struct yaffs_dev *my_dev; /* The device I'm on */ + + struct list_head hash_link; /* list of objects in hash bucket */ + + struct list_head hard_links; /* hard linked object chain*/ + + /* directory structure stuff */ + /* also used for linking up the free list */ + struct yaffs_obj *parent; + struct list_head siblings; + + /* Where's my object header in NAND? */ + int hdr_chunk; + + int n_data_chunks; /* Number of data chunks for this file. */ + + u32 obj_id; /* the object id value */ + + u32 yst_mode; + + YCHAR short_name[YAFFS_SHORT_NAME_LENGTH + 1]; + +#ifdef CONFIG_YAFFS_WINCE + u32 win_ctime[2]; + u32 win_mtime[2]; + u32 win_atime[2]; +#else + u32 yst_uid; + u32 yst_gid; + u32 yst_atime; + u32 yst_mtime; + u32 yst_ctime; +#endif + + u32 yst_rdev; + + void *my_inode; + + enum yaffs_obj_type variant_type; + + union yaffs_obj_var variant; + +}; + +struct yaffs_obj_bucket { + struct list_head list; + int count; +}; + +/* yaffs_checkpt_obj holds the definition of an object as dumped + * by checkpointing. + */ + +struct yaffs_checkpt_obj { + int struct_type; + u32 obj_id; + u32 parent_id; + int hdr_chunk; + enum yaffs_obj_type variant_type:3; + u8 deleted:1; + u8 soft_del:1; + u8 unlinked:1; + u8 fake:1; + u8 rename_allowed:1; + u8 unlink_allowed:1; + u8 serial; + int n_data_chunks; + loff_t size_or_equiv_obj; +}; + +/*--------------------- Temporary buffers ---------------- + * + * These are chunk-sized working buffers. Each device has a few. + */ + +struct yaffs_buffer { + u8 *buffer; + int in_use; +}; + +/*----------------- Device ---------------------------------*/ + +struct yaffs_param { + const YCHAR *name; + + /* + * Entry parameters set up way early. Yaffs sets up the rest. + * The structure should be zeroed out before use so that unused + * and defualt values are zero. + */ + + int inband_tags; /* Use unband tags */ + u32 total_bytes_per_chunk; /* Should be >= 512, does not need to + be a power of 2 */ + int chunks_per_block; /* does not need to be a power of 2 */ + int spare_bytes_per_chunk; /* spare area size */ + int start_block; /* Start block we're allowed to use */ + int end_block; /* End block we're allowed to use */ + int n_reserved_blocks; /* Tuneable so that we can reduce + * reserved blocks on NOR and RAM. */ + + int n_caches; /* If <= 0, then short op caching is disabled, + * else the number of short op caches. + */ + int use_nand_ecc; /* Flag to decide whether or not to use + * NAND driver ECC on data (yaffs1) */ + int tags_9bytes; /* Use 9 byte tags */ + int no_tags_ecc; /* Flag to decide whether or not to do ECC + * on packed tags (yaffs2) */ + + int is_yaffs2; /* Use yaffs2 mode on this device */ + + int empty_lost_n_found; /* Auto-empty lost+found directory on mount */ + + int refresh_period; /* How often to check for a block refresh */ + + /* Checkpoint control. Can be set before or after initialisation */ + u8 skip_checkpt_rd; + u8 skip_checkpt_wr; + + int enable_xattr; /* Enable xattribs */ + + /* NAND access functions (Must be set before calling YAFFS) */ + + int (*write_chunk_fn) (struct yaffs_dev *dev, + int nand_chunk, const u8 *data, + const struct yaffs_spare *spare); + int (*read_chunk_fn) (struct yaffs_dev *dev, + int nand_chunk, u8 *data, + struct yaffs_spare *spare); + int (*erase_fn) (struct yaffs_dev *dev, int flash_block); + int (*initialise_flash_fn) (struct yaffs_dev *dev); + int (*deinitialise_flash_fn) (struct yaffs_dev *dev); + + /* yaffs2 mode functions */ + int (*write_chunk_tags_fn) (struct yaffs_dev *dev, + int nand_chunk, const u8 *data, + const struct yaffs_ext_tags *tags); + int (*read_chunk_tags_fn) (struct yaffs_dev *dev, + int nand_chunk, u8 *data, + struct yaffs_ext_tags *tags); + int (*bad_block_fn) (struct yaffs_dev *dev, int block_no); + int (*query_block_fn) (struct yaffs_dev *dev, int block_no, + enum yaffs_block_state *state, + u32 *seq_number); + + /* The remove_obj_fn function must be supplied by OS flavours that + * need it. + * yaffs direct uses it to implement the faster readdir. + * Linux uses it to protect the directory during unlocking. + */ + void (*remove_obj_fn) (struct yaffs_obj *obj); + + /* Callback to mark the superblock dirty */ + void (*sb_dirty_fn) (struct yaffs_dev *dev); + + /* Callback to control garbage collection. */ + unsigned (*gc_control) (struct yaffs_dev *dev); + + /* Debug control flags. Don't use unless you know what you're doing */ + int use_header_file_size; /* Flag to determine if we should use + * file sizes from the header */ + int disable_lazy_load; /* Disable lazy loading on this device */ + int wide_tnodes_disabled; /* Set to disable wide tnodes */ + int disable_soft_del; /* yaffs 1 only: Set to disable the use of + * softdeletion. */ + + int defered_dir_update; /* Set to defer directory updates */ + +#ifdef CONFIG_YAFFS_AUTO_UNICODE + int auto_unicode; +#endif + int always_check_erased; /* Force chunk erased check always on */ + + int disable_summary; + + int max_objects; /* + * Set to limit the number of objects created. + * 0 = no limit. + */ +}; + +struct yaffs_dev { + struct yaffs_param param; + + /* Context storage. Holds extra OS specific data for this device */ + + void *os_context; + void *driver_context; + + struct list_head dev_list; + + /* Runtime parameters. Set up by YAFFS. */ + int data_bytes_per_chunk; + + /* Non-wide tnode stuff */ + u16 chunk_grp_bits; /* Number of bits that need to be resolved if + * the tnodes are not wide enough. + */ + u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ + + /* Stuff to support wide tnodes */ + u32 tnode_width; + u32 tnode_mask; + u32 tnode_size; + + /* Stuff for figuring out file offset to chunk conversions */ + u32 chunk_shift; /* Shift value */ + u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */ + u32 chunk_mask; /* Mask to use for power-of-2 case */ + + int is_mounted; + int read_only; + int is_checkpointed; + + /* Stuff to support block offsetting to support start block zero */ + int internal_start_block; + int internal_end_block; + int block_offset; + int chunk_offset; + + /* Runtime checkpointing stuff */ + int checkpt_page_seq; /* running sequence number of checkpt pages */ + int checkpt_byte_count; + int checkpt_byte_offs; + u8 *checkpt_buffer; + int checkpt_open_write; + int blocks_in_checkpt; + int checkpt_cur_chunk; + int checkpt_cur_block; + int checkpt_next_block; + int *checkpt_block_list; + int checkpt_max_blocks; + u32 checkpt_sum; + u32 checkpt_xor; + + int checkpoint_blocks_required; /* Number of blocks needed to store + * current checkpoint set */ + + /* Block Info */ + struct yaffs_block_info *block_info; + u8 *chunk_bits; /* bitmap of chunks in use */ + unsigned block_info_alt:1; /* allocated using alternative alloc */ + unsigned chunk_bits_alt:1; /* allocated using alternative alloc */ + int chunk_bit_stride; /* Number of bytes of chunk_bits per block. + * Must be consistent with chunks_per_block. + */ + + int n_erased_blocks; + int alloc_block; /* Current block being allocated off */ + u32 alloc_page; + int alloc_block_finder; /* Used to search for next allocation block */ + + /* Object and Tnode memory management */ + void *allocator; + int n_obj; + int n_tnodes; + + int n_hardlinks; + + struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; + u32 bucket_finder; + + int n_free_chunks; + + /* Garbage collection control */ + u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ + u32 n_clean_ups; + + unsigned has_pending_prioritised_gc; /* We think this device might + have pending prioritised gcs */ + unsigned gc_disable; + unsigned gc_block_finder; + unsigned gc_dirtiest; + unsigned gc_pages_in_use; + unsigned gc_not_done; + unsigned gc_block; + unsigned gc_chunk; + unsigned gc_skip; + struct yaffs_summary_tags *gc_sum_tags; + + /* Special directories */ + struct yaffs_obj *root_dir; + struct yaffs_obj *lost_n_found; + + int buffered_block; /* Which block is buffered here? */ + int doing_buffered_block_rewrite; + + struct yaffs_cache *cache; + int cache_last_use; + + /* Stuff for background deletion and unlinked files. */ + struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted + files live. */ + struct yaffs_obj *del_dir; /* Directory where deleted objects are + sent to disappear. */ + struct yaffs_obj *unlinked_deletion; /* Current file being + background deleted. */ + int n_deleted_files; /* Count of files awaiting deletion; */ + int n_unlinked_files; /* Count of unlinked files. */ + int n_bg_deletions; /* Count of background deletions. */ + + /* Temporary buffer management */ + struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; + int max_temp; + int temp_in_use; + int unmanaged_buffer_allocs; + int unmanaged_buffer_deallocs; + + /* yaffs2 runtime stuff */ + unsigned seq_number; /* Sequence number of currently + allocating block */ + unsigned oldest_dirty_seq; + unsigned oldest_dirty_block; + + /* Block refreshing */ + int refresh_skip; /* A skip down counter. + * Refresh happens when this gets to zero. */ + + /* Dirty directory handling */ + struct list_head dirty_dirs; /* List of dirty directories */ + + /* Summary */ + int chunks_per_summary; + struct yaffs_summary_tags *sum_tags; + + /* Statistics */ + u32 n_page_writes; + u32 n_page_reads; + u32 n_erasures; + u32 n_erase_failures; + u32 n_gc_copies; + u32 all_gcs; + u32 passive_gc_count; + u32 oldest_dirty_gc_count; + u32 n_gc_blocks; + u32 bg_gcs; + u32 n_retried_writes; + u32 n_retired_blocks; + u32 n_ecc_fixed; + u32 n_ecc_unfixed; + u32 n_tags_ecc_fixed; + u32 n_tags_ecc_unfixed; + u32 n_deletions; + u32 n_unmarked_deletions; + u32 refresh_count; + u32 cache_hits; + u32 tags_used; + u32 summary_used; + +}; + +/* The CheckpointDevice structure holds the device information that changes + *at runtime and must be preserved over unmount/mount cycles. + */ +struct yaffs_checkpt_dev { + int struct_type; + int n_erased_blocks; + int alloc_block; /* Current block being allocated off */ + u32 alloc_page; + int n_free_chunks; + + int n_deleted_files; /* Count of files awaiting deletion; */ + int n_unlinked_files; /* Count of unlinked files. */ + int n_bg_deletions; /* Count of background deletions. */ + + /* yaffs2 runtime stuff */ + unsigned seq_number; /* Sequence number of currently + * allocating block */ + +}; + +struct yaffs_checkpt_validity { + int struct_type; + u32 magic; + u32 version; + u32 head; +}; + +struct yaffs_shadow_fixer { + int obj_id; + int shadowed_id; + struct yaffs_shadow_fixer *next; +}; + +/* Structure for doing xattr modifications */ +struct yaffs_xattr_mod { + int set; /* If 0 then this is a deletion */ + const YCHAR *name; + const void *data; + int size; + int flags; + int result; +}; + +/*----------------------- YAFFS Functions -----------------------*/ + +int yaffs_guts_initialise(struct yaffs_dev *dev); +void yaffs_deinitialise(struct yaffs_dev *dev); + +int yaffs_get_n_free_chunks(struct yaffs_dev *dev); + +int yaffs_rename_obj(struct yaffs_obj *old_dir, const YCHAR * old_name, + struct yaffs_obj *new_dir, const YCHAR * new_name); + +int yaffs_unlinker(struct yaffs_obj *dir, const YCHAR * name); +int yaffs_del_obj(struct yaffs_obj *obj); + +int yaffs_get_obj_name(struct yaffs_obj *obj, YCHAR * name, int buffer_size); +loff_t yaffs_get_obj_length(struct yaffs_obj *obj); +int yaffs_get_obj_inode(struct yaffs_obj *obj); +unsigned yaffs_get_obj_type(struct yaffs_obj *obj); +int yaffs_get_obj_link_count(struct yaffs_obj *obj); + +/* File operations */ +int yaffs_file_rd(struct yaffs_obj *obj, u8 * buffer, loff_t offset, + int n_bytes); +int yaffs_wr_file(struct yaffs_obj *obj, const u8 * buffer, loff_t offset, + int n_bytes, int write_trhrough); +int yaffs_resize_file(struct yaffs_obj *obj, loff_t new_size); + +struct yaffs_obj *yaffs_create_file(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid); + +int yaffs_flush_file(struct yaffs_obj *obj, int update_time, int data_sync); + +/* Flushing and checkpointing */ +void yaffs_flush_whole_cache(struct yaffs_dev *dev); + +int yaffs_checkpoint_save(struct yaffs_dev *dev); +int yaffs_checkpoint_restore(struct yaffs_dev *dev); + +/* Directory operations */ +struct yaffs_obj *yaffs_create_dir(struct yaffs_obj *parent, const YCHAR *name, + u32 mode, u32 uid, u32 gid); +struct yaffs_obj *yaffs_find_by_name(struct yaffs_obj *the_dir, + const YCHAR *name); +struct yaffs_obj *yaffs_find_by_number(struct yaffs_dev *dev, u32 number); + +/* Link operations */ +struct yaffs_obj *yaffs_link_obj(struct yaffs_obj *parent, const YCHAR *name, + struct yaffs_obj *equiv_obj); + +struct yaffs_obj *yaffs_get_equivalent_obj(struct yaffs_obj *obj); + +/* Symlink operations */ +struct yaffs_obj *yaffs_create_symlink(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, const YCHAR *alias); +YCHAR *yaffs_get_symlink_alias(struct yaffs_obj *obj); + +/* Special inodes (fifos, sockets and devices) */ +struct yaffs_obj *yaffs_create_special(struct yaffs_obj *parent, + const YCHAR *name, u32 mode, u32 uid, + u32 gid, u32 rdev); + +int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name, + const void *value, int size, int flags); +int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value, + int size); +int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); +int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name); + +/* Special directories */ +struct yaffs_obj *yaffs_root(struct yaffs_dev *dev); +struct yaffs_obj *yaffs_lost_n_found(struct yaffs_dev *dev); + +void yaffs_handle_defered_free(struct yaffs_obj *obj); + +void yaffs_update_dirty_dirs(struct yaffs_dev *dev); + +int yaffs_bg_gc(struct yaffs_dev *dev, unsigned urgency); + +/* Debug dump */ +int yaffs_dump_obj(struct yaffs_obj *obj); + +void yaffs_guts_test(struct yaffs_dev *dev); + +/* A few useful functions to be used within the core files*/ +void yaffs_chunk_del(struct yaffs_dev *dev, int chunk_id, int mark_flash, + int lyn); +int yaffs_check_ff(u8 *buffer, int n_bytes); +void yaffs_handle_chunk_error(struct yaffs_dev *dev, + struct yaffs_block_info *bi); + +u8 *yaffs_get_temp_buffer(struct yaffs_dev *dev); +void yaffs_release_temp_buffer(struct yaffs_dev *dev, u8 *buffer); + +struct yaffs_obj *yaffs_find_or_create_by_number(struct yaffs_dev *dev, + int number, + enum yaffs_obj_type type); +int yaffs_put_chunk_in_file(struct yaffs_obj *in, int inode_chunk, + int nand_chunk, int in_scan); +void yaffs_set_obj_name(struct yaffs_obj *obj, const YCHAR *name); +void yaffs_set_obj_name_from_oh(struct yaffs_obj *obj, + const struct yaffs_obj_hdr *oh); +void yaffs_add_obj_to_dir(struct yaffs_obj *directory, struct yaffs_obj *obj); +YCHAR *yaffs_clone_str(const YCHAR *str); +void yaffs_link_fixup(struct yaffs_dev *dev, struct list_head *hard_list); +void yaffs_block_became_dirty(struct yaffs_dev *dev, int block_no); +int yaffs_update_oh(struct yaffs_obj *in, const YCHAR *name, + int force, int is_shrink, int shadows, + struct yaffs_xattr_mod *xop); +void yaffs_handle_shadowed_obj(struct yaffs_dev *dev, int obj_id, + int backward_scanning); +int yaffs_check_alloc_available(struct yaffs_dev *dev, int n_chunks); +struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev); +struct yaffs_tnode *yaffs_add_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id, + struct yaffs_tnode *passed_tn); + +int yaffs_do_file_wr(struct yaffs_obj *in, const u8 *buffer, loff_t offset, + int n_bytes, int write_trhrough); +void yaffs_resize_file_down(struct yaffs_obj *obj, loff_t new_size); +void yaffs_skip_rest_of_block(struct yaffs_dev *dev); + +int yaffs_count_free_chunks(struct yaffs_dev *dev); + +struct yaffs_tnode *yaffs_find_tnode_0(struct yaffs_dev *dev, + struct yaffs_file_var *file_struct, + u32 chunk_id); + +u32 yaffs_get_group_base(struct yaffs_dev *dev, struct yaffs_tnode *tn, + unsigned pos); + +int yaffs_is_non_empty_dir(struct yaffs_obj *obj); + +int yaffs_format_dev(struct yaffs_dev *dev); + +void yaffs_addr_to_chunk(struct yaffs_dev *dev, loff_t addr, + int *chunk_out, u32 *offset_out); +/* + * Marshalling functions to get loff_t file sizes into aand out of + * object headers. + */ +void yaffs_oh_size_load(struct yaffs_obj_hdr *oh, loff_t fsize); +loff_t yaffs_oh_to_size(struct yaffs_obj_hdr *oh); +loff_t yaffs_max_file_size(struct yaffs_dev *dev); + + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c new file mode 100644 index 0000000..7e2c250 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.c @@ -0,0 +1,53 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +/* These functions have been renamed to hweightxx to match the + * equivaqlent functions in the Linux kernel. + */ + +#include "yaffs_hweight.h" + +static const char yaffs_count_bits_table[256] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 +}; + +int yaffs_hweight8(u8 x) +{ + int ret_val; + ret_val = yaffs_count_bits_table[x]; + return ret_val; +} + +int yaffs_hweight32(u32 x) +{ + return yaffs_hweight8(x & 0xff) + + yaffs_hweight8((x >> 8) & 0xff) + + yaffs_hweight8((x >> 16) & 0xff) + + yaffs_hweight8((x >> 24) & 0xff); +} + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h new file mode 100644 index 0000000..3f7c6c3 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_hweight.h @@ -0,0 +1,24 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_HWEIGHT_H__ +#define __YAFFS_HWEIGHT_H__ + +#include "yportenv.h" + +int yaffs_hweight8(u8 x); +int yaffs_hweight32(u32 x); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c new file mode 100644 index 0000000..421a2a5 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.c @@ -0,0 +1,144 @@ + +#include "yaffs_k9f2g08.h" +#include "k9f2g08_api.h" +#include "yaffs_packedtags2.h" +#include "yaffs_trace.h" + +int ynf_init(struct yaffs_dev *dev) +{ + yaffs_trace(YAFFS_TRACE_MTD, "ynf_init on %s", dev->param.name); + return YAFFS_OK; +} + +int ynf_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, const u8 *data, const struct yaffs_ext_tags *tags) +{ + struct yaffs_packed_tags2 pt; + void *spare; + unsigned spareSize = 0; + + yaffs_trace(YAFFS_TRACE_MTD, "ynf_write_chunk_tags chunk %d data %p tags %p", nand_chunk, data, tags); + + /* For yaffs2 writing there must be both data and tags. + * If we're using inband tags, then the tags are stuffed into + * the end of the data buffer. + */ + if(dev->param.inband_tags){ + struct yaffs_packed_tags2_tags_only *pt2tp; + pt2tp = (struct yaffs_packed_tags2_tags_only *) + (data + dev->data_bytes_per_chunk); + yaffs_pack_tags2_tags_only(pt2tp,tags); + spare = NULL; + spareSize = 0; + } + else{ + yaffs_pack_tags2(&pt, tags,!dev->param.no_tags_ecc); + spare = &pt; + spareSize = sizeof(struct yaffs_packed_tags2); + } + + return k9f2g08_write(nand_chunk, data, spare, spareSize); +} + +int ynf_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, u8 *data, struct yaffs_ext_tags *tags) +{ + struct yaffs_packed_tags2 pt; + int localData = 0; + void *spare = NULL; + unsigned spareSize; + int retval = 0; + int eccStatus; //0 = ok, 1 = fixed, -1 = unfixed + + yaffs_trace(YAFFS_TRACE_MTD, "ynf_read_chunk_tags chunk %d data %p tags %p", nand_chunk, data, tags); + + if(!tags){ + spare = NULL; + spareSize = 0; + }else if(dev->param.inband_tags){ + + if(!data) { + localData = 1; + data = yaffs_get_temp_buffer(dev); + } + spare = NULL; + spareSize = 0; + } + else { + spare = &pt; + spareSize = sizeof(struct yaffs_packed_tags2); + } + + retval = k9f2g08_read(nand_chunk, data, spare, spareSize, &eccStatus); + + if(dev->param.inband_tags){ + if(tags){ + struct yaffs_packed_tags2_tags_only * pt2tp; + pt2tp = (struct yaffs_packed_tags2_tags_only *)&data[dev->data_bytes_per_chunk]; + yaffs_unpack_tags2_tags_only(tags,pt2tp); + } + } + else { + if (tags){ + yaffs_unpack_tags2(tags, &pt,!dev->param.no_tags_ecc); + } + } + + + if(tags && tags->chunk_used){ + if(eccStatus < 0 || + tags->ecc_result == YAFFS_ECC_RESULT_UNFIXED) + tags->ecc_result = YAFFS_ECC_RESULT_UNFIXED; + else if(eccStatus > 0 || + tags->ecc_result == YAFFS_ECC_RESULT_FIXED) + tags->ecc_result = YAFFS_ECC_RESULT_FIXED; + else + tags->ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + } + + if(localData) + yaffs_release_temp_buffer(dev, data); + + return retval; +} + +int ynf_mark_block_bad(struct yaffs_dev *dev, int blockId) +{ + yaffs_trace(YAFFS_TRACE_MTD, "ynf_mark_block_bad block@%d ", blockId); + return k9f2g08_mark_block_bad(blockId); +} + +int ynf_erase_block(struct yaffs_dev *dev, int blockId) +{ + yaffs_trace(YAFFS_TRACE_MTD, "ynf_erase_block block@%d ", blockId); + return k9f2g08_erase_block(blockId); +} + + +int ynf_query_block(struct yaffs_dev *dev, int blockId, enum yaffs_block_state *state, u32 *seq_number) +{ + unsigned chunkNo; + struct yaffs_ext_tags tags; + + yaffs_trace(YAFFS_TRACE_MTD, "ynf_query_block block@%d ", blockId); + *seq_number = 0; + + chunkNo = blockId * dev->param.chunks_per_block; + + if (!k9f2g08_is_block_ok(blockId)) { + *state = YAFFS_BLOCK_STATE_DEAD; + return YAFFS_OK; + } + + ynf_read_chunk_tags(dev, chunkNo, NULL, &tags); + if(!tags.chunk_used) + { + *state = YAFFS_BLOCK_STATE_EMPTY; + } + else + { + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; + *seq_number = tags.seq_number; + } + return YAFFS_OK; +} + + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h new file mode 100644 index 0000000..54252df --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_k9f2g08.h @@ -0,0 +1,13 @@ +#ifndef __YAFFS_K9F2G08_H__ +#define __YAFFS_K9F2G08_H__ + +#include "yaffs_guts.h" + +int ynf_init(struct yaffs_dev *dev); +int ynf_mark_block_bad(struct yaffs_dev *dev,int blockNumber); +int ynf_query_block(struct yaffs_dev *dev, int block_no, enum yaffs_block_state *state, u32 *seq_number); +int ynf_write_chunk_tags(struct yaffs_dev *dev,int nand_chunk,const u8 *data, const struct yaffs_ext_tags *tags); +int ynf_read_chunk_tags(struct yaffs_dev *dev,int nand_chunk, u8 *data, struct yaffs_ext_tags *tags); +int ynf_erase_block(struct yaffs_dev *dev, int block_num); + +#endif /* __YAFFS_K9F2G08_H__ */ diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h new file mode 100644 index 0000000..a7afaea --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_list.h @@ -0,0 +1,126 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * This file is just holds extra declarations of macros that would normally + * be providesd in the Linux kernel. These macros have been written from + * scratch but are functionally equivalent to the Linux ones. + * + */ + +#ifndef __YAFFS_LIST_H__ +#define __YAFFS_LIST_H__ + + +/* + * This is a simple doubly linked list implementation that matches the + * way the Linux kernel doubly linked list implementation works. + */ + +struct list_head { + struct list_head *next; /* next in chain */ + struct list_head *prev; /* previous in chain */ +}; + + +/* Initialise a static list */ +#define LIST_HEAD(name) \ +struct list_head name = { &(name), &(name)} + + + +/* Initialise a list head to an empty list */ +#define INIT_LIST_HEAD(p) \ +do { \ + (p)->next = (p);\ + (p)->prev = (p); \ +} while (0) + + +/* Add an element to a list */ +static inline void list_add(struct list_head *new_entry, + struct list_head *list) +{ + struct list_head *list_next = list->next; + + list->next = new_entry; + new_entry->prev = list; + new_entry->next = list_next; + list_next->prev = new_entry; + +} + +static inline void list_add_tail(struct list_head *new_entry, + struct list_head *list) +{ + struct list_head *list_prev = list->prev; + + list->prev = new_entry; + new_entry->next = list; + new_entry->prev = list_prev; + list_prev->next = new_entry; + +} + + +/* Take an element out of its current list, with or without + * reinitialising the links.of the entry*/ +static inline void list_del(struct list_head *entry) +{ + struct list_head *list_next = entry->next; + struct list_head *list_prev = entry->prev; + + list_next->prev = list_prev; + list_prev->next = list_next; + +} + +static inline void list_del_init(struct list_head *entry) +{ + list_del(entry); + entry->next = entry->prev = entry; +} + + +/* Test if the list is empty */ +static inline int list_empty(struct list_head *entry) +{ + return (entry->next == entry); +} + + +/* list_entry takes a pointer to a list entry and offsets it to that + * we can find a pointer to the object it is embedded in. + */ + + +#define list_entry(entry, type, member) \ + ((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member))) + + +/* list_for_each and list_for_each_safe iterate over lists. + * list_for_each_safe uses temporary storage to make the list delete safe + */ + +#define list_for_each(itervar, list) \ + for (itervar = (list)->next; itervar != (list); itervar = itervar->next) + +#define list_for_each_safe(itervar, save_var, list) \ + for (itervar = (list)->next, save_var = (list)->next->next; \ + itervar != (list); \ + itervar = save_var, save_var = save_var->next) + + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c new file mode 100644 index 0000000..4bdf4ed --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.c @@ -0,0 +1,208 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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 simple implementation of a name-value store assumes a small number of +* values and fits into a small finite buffer. + * + * Each attribute is stored as a record: + * sizeof(int) bytes record size. + * strnlen+1 bytes name null terminated. + * nbytes value. + * ---------- + * total size stored in record size + * + * This code has not been tested with unicode yet. + */ + +#include "yaffs_nameval.h" + +#include "yportenv.h" + +static int nval_find(const char *xb, int xb_size, const YCHAR *name, + int *exist_size) +{ + int pos = 0; + int size; + + memcpy(&size, xb, sizeof(int)); + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { + if (!strncmp((YCHAR *) (xb + pos + sizeof(int)), + name, size)) { + if (exist_size) + *exist_size = size; + return pos; + } + pos += size; + if (pos < xb_size - sizeof(int)) + memcpy(&size, xb + pos, sizeof(int)); + else + size = 0; + } + if (exist_size) + *exist_size = 0; + return -ENODATA; +} + +static int nval_used(const char *xb, int xb_size) +{ + int pos = 0; + int size; + + memcpy(&size, xb + pos, sizeof(int)); + while (size > 0 && (size < xb_size) && (pos + size < xb_size)) { + pos += size; + if (pos < xb_size - sizeof(int)) + memcpy(&size, xb + pos, sizeof(int)); + else + size = 0; + } + return pos; +} + +int nval_del(char *xb, int xb_size, const YCHAR *name) +{ + int pos = nval_find(xb, xb_size, name, NULL); + int size; + + if (pos < 0 || pos >= xb_size) + return -ENODATA; + + /* Find size, shift rest over this record, + * then zero out the rest of buffer */ + memcpy(&size, xb + pos, sizeof(int)); + memcpy(xb + pos, xb + pos + size, xb_size - (pos + size)); + memset(xb + (xb_size - size), 0, size); + return 0; +} + +int nval_set(char *xb, int xb_size, const YCHAR *name, const char *buf, + int bsize, int flags) +{ + int pos; + int namelen = strnlen(name, xb_size); + int reclen; + int size_exist = 0; + int space; + int start; + + pos = nval_find(xb, xb_size, name, &size_exist); + + if (flags & XATTR_CREATE && pos >= 0) + return -EEXIST; + if (flags & XATTR_REPLACE && pos < 0) + return -ENODATA; + + start = nval_used(xb, xb_size); + space = xb_size - start + size_exist; + + reclen = (sizeof(int) + namelen + 1 + bsize); + + if (reclen > space) + return -ENOSPC; + + if (pos >= 0) { + nval_del(xb, xb_size, name); + start = nval_used(xb, xb_size); + } + + pos = start; + + memcpy(xb + pos, &reclen, sizeof(int)); + pos += sizeof(int); + strncpy((YCHAR *) (xb + pos), name, reclen); + pos += (namelen + 1); + memcpy(xb + pos, buf, bsize); + return 0; +} + +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, + int bsize) +{ + int pos = nval_find(xb, xb_size, name, NULL); + int size; + + if (pos >= 0 && pos < xb_size) { + + memcpy(&size, xb + pos, sizeof(int)); + pos += sizeof(int); /* advance past record length */ + size -= sizeof(int); + + /* Advance over name string */ + while (xb[pos] && size > 0 && pos < xb_size) { + pos++; + size--; + } + /*Advance over NUL */ + pos++; + size--; + + /* If bsize is zero then this is a size query. + * Return the size, but don't copy. + */ + if (!bsize) + return size; + + if (size <= bsize) { + memcpy(buf, xb + pos, size); + return size; + } + } + if (pos >= 0) + return -ERANGE; + + return -ENODATA; +} + +int nval_list(const char *xb, int xb_size, char *buf, int bsize) +{ + int pos = 0; + int size; + int name_len; + int ncopied = 0; + int filled = 0; + + memcpy(&size, xb + pos, sizeof(int)); + while (size > sizeof(int) && + size <= xb_size && + (pos + size) < xb_size && + !filled) { + pos += sizeof(int); + size -= sizeof(int); + name_len = strnlen((YCHAR *) (xb + pos), size); + if (ncopied + name_len + 1 < bsize) { + memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); + buf += name_len; + *buf = '\0'; + buf++; + if (sizeof(YCHAR) > 1) { + *buf = '\0'; + buf++; + } + ncopied += (name_len + 1); + } else { + filled = 1; + } + pos += size; + if (pos < xb_size - sizeof(int)) + memcpy(&size, xb + pos, sizeof(int)); + else + size = 0; + } + return ncopied; +} + +int nval_hasvalues(const char *xb, int xb_size) +{ + return nval_used(xb, xb_size) > 0; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h new file mode 100644 index 0000000..951e64f --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nameval.h @@ -0,0 +1,28 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __NAMEVAL_H__ +#define __NAMEVAL_H__ + +#include "yportenv.h" + +int nval_del(char *xb, int xb_size, const YCHAR * name); +int nval_set(char *xb, int xb_size, const YCHAR * name, const char *buf, + int bsize, int flags); +int nval_get(const char *xb, int xb_size, const YCHAR * name, char *buf, + int bsize); +int nval_list(const char *xb, int xb_size, char *buf, int bsize); +int nval_hasvalues(const char *xb, int xb_size); +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c new file mode 100644 index 0000000..165d010 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.c @@ -0,0 +1,120 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_nand.h" +#include "yaffs_tagscompat.h" + +#include "yaffs_getblockinfo.h" +#include "yaffs_summary.h" + +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, + u8 *buffer, struct yaffs_ext_tags *tags) +{ + int result; + struct yaffs_ext_tags local_tags; + int flash_chunk = nand_chunk - dev->chunk_offset; + + dev->n_page_reads++; + + /* If there are no tags provided use local tags. */ + if (!tags) + tags = &local_tags; + + if (dev->param.read_chunk_tags_fn) + result = + dev->param.read_chunk_tags_fn(dev, flash_chunk, buffer, + tags); + else + result = yaffs_tags_compat_rd(dev, + flash_chunk, buffer, tags); + if (tags && tags->ecc_result > YAFFS_ECC_RESULT_NO_ERROR) { + + struct yaffs_block_info *bi; + bi = yaffs_get_block_info(dev, + nand_chunk / + dev->param.chunks_per_block); + yaffs_handle_chunk_error(dev, bi); + } + return result; +} + +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, + int nand_chunk, + const u8 *buffer, struct yaffs_ext_tags *tags) +{ + int result; + int flash_chunk = nand_chunk - dev->chunk_offset; + + dev->n_page_writes++; + + if (tags) { + tags->seq_number = dev->seq_number; + tags->chunk_used = 1; + yaffs_trace(YAFFS_TRACE_WRITE, + "Writing chunk %d tags %d %d", + nand_chunk, tags->obj_id, tags->chunk_id); + } else { + yaffs_trace(YAFFS_TRACE_ERROR, "Writing with no tags"); + BUG(); + return YAFFS_FAIL; + } + + if (dev->param.write_chunk_tags_fn) + result = dev->param.write_chunk_tags_fn(dev, flash_chunk, + buffer, tags); + else + result = yaffs_tags_compat_wr(dev, flash_chunk, buffer, tags); + + yaffs_summary_add(dev, tags, nand_chunk); + + return result; +} + +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no) +{ + block_no -= dev->block_offset; + if (dev->param.bad_block_fn) + return dev->param.bad_block_fn(dev, block_no); + + return yaffs_tags_compat_mark_bad(dev, block_no); +} + +int yaffs_query_init_block_state(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 *seq_number) +{ + block_no -= dev->block_offset; + if (dev->param.query_block_fn) + return dev->param.query_block_fn(dev, block_no, state, + seq_number); + + return yaffs_tags_compat_query_block(dev, block_no, state, seq_number); +} + +int yaffs_erase_block(struct yaffs_dev *dev, int flash_block) +{ + int result; + + flash_block -= dev->block_offset; + dev->n_erasures++; + result = dev->param.erase_fn(dev, flash_block); + return result; +} + +int yaffs_init_nand(struct yaffs_dev *dev) +{ + if (dev->param.initialise_flash_fn) + return dev->param.initialise_flash_fn(dev); + return YAFFS_OK; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h new file mode 100644 index 0000000..7134662 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_nand.h @@ -0,0 +1,38 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_NAND_H__ +#define __YAFFS_NAND_H__ +#include "yaffs_guts.h" + +int yaffs_rd_chunk_tags_nand(struct yaffs_dev *dev, int nand_chunk, + u8 *buffer, struct yaffs_ext_tags *tags); + +int yaffs_wr_chunk_tags_nand(struct yaffs_dev *dev, + int nand_chunk, + const u8 *buffer, struct yaffs_ext_tags *tags); + +int yaffs_mark_bad(struct yaffs_dev *dev, int block_no); + +int yaffs_query_init_block_state(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + unsigned *seq_number); + +int yaffs_erase_block(struct yaffs_dev *dev, int flash_block); + +int yaffs_init_nand(struct yaffs_dev *dev); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c new file mode 100644 index 0000000..d24a7b7 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.c @@ -0,0 +1,170 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +/* + * Example OS glue functions for running on a Linux/POSIX system. + */ + +#include "yaffscfg.h" +#include "yaffs_guts.h" +#include "yaffsfs.h" +#include "yaffs_trace.h" +#include "yportenv.h" + + +/* + * yaffsfs_SetError() and yaffsfs_GetError() + * Do whatever to set the system error. + * yaffsfs_GetError() just fetches the last error. + */ +static int errno; + +static int yaffsfs_lastError; + +void yaffsfs_SetError(int err) +{ + //Do whatever to set error + yaffsfs_lastError = err; + errno = err; +} + +int yaffsfs_GetLastError(void) +{ + return yaffsfs_lastError; +} + +/* + * yaffsfs_CheckMemRegion() + * Check that access to an address is valid. + * This can check memory is in bounds and is writable etc. + * + * Returns 0 if ok, negative if not. + */ +int yaffsfs_CheckMemRegion(const void *addr, size_t size, int write_request) +{ + if(!addr) + return -1; + return 0; +} + +/* + * yaffsfs_Lock() + * yaffsfs_Unlock() + * A single mechanism to lock and unlock yaffs. Hook up to a mutex or whatever. + * Here are two examples, one using POSIX pthreads, the other doing nothing. + */ + +#ifdef CONFIG_YAFFS_USE_PTHREADS +#include <pthread.h> +static pthread_mutex_t mutex1; + + +void yaffsfs_Lock(void) +{ + pthread_mutex_lock( &mutex1 ); +} + +void yaffsfs_Unlock(void) +{ + pthread_mutex_unlock( &mutex1 ); +} + +void yaffsfs_LockInit(void) +{ + pthread_mutex_init( &mutex1, NULL); +} + +#else + +void yaffsfs_Lock(void) +{ +} + +void yaffsfs_Unlock(void) +{ +} + +void yaffsfs_LockInit(void) +{ +} +#endif + +/* + * yaffsfs_CurrentTime() retrns a 32-bit timestamp. + * + * Can return 0 if your system does not care about time. + */ + +u32 yaffsfs_CurrentTime(void) +{ + return 0; + //return time(NULL); +} + + +/* + * yaffsfs_malloc() + * yaffsfs_free() + * + * Functions to allocate and free memory. + */ + +#ifdef CONFIG_YAFFS_TEST_MALLOC + +static int yaffs_kill_alloc = 0; +static size_t total_malloced = 0; +static size_t malloc_limit = 0 & 6000000; + +void *yaffsfs_malloc(size_t size) +{ + void * this; + if(yaffs_kill_alloc) + return NULL; + if(malloc_limit && malloc_limit <(total_malloced + size) ) + return NULL; + + this = malloc(size); + if(this) + total_malloced += size; + return this; +} + +#else + +void *yaffsfs_malloc(size_t size) +{ + return malloc(size); +} + +#endif + +void yaffsfs_free(void *ptr) +{ + free(ptr); +} + +void yaffsfs_OSInitialisation(void) +{ + yaffsfs_LockInit(); +} + +/* + * yaffs_bug_fn() + * Function to report a bug. + */ + +void yaffs_bug_fn(const char *file_name, int line_no) +{ + printf("yaffs bug detected %s:%d\n", + file_name, line_no); +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h new file mode 100644 index 0000000..739dddb --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_osglue.h @@ -0,0 +1,44 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * Header file for using yaffs in an application via + * a direct interface. + */ + + +#ifndef __YAFFS_OSGLUE_H__ +#define __YAFFS_OSGLUE_H__ + + +#include "yportenv.h" + +void yaffsfs_Lock(void); +void yaffsfs_Unlock(void); + +u32 yaffsfs_CurrentTime(void); + +void yaffsfs_SetError(int err); + +void *yaffsfs_malloc(size_t size); +void yaffsfs_free(void *ptr); + +int yaffsfs_CheckMemRegion(const void *addr, size_t size, int write_request); + +void yaffsfs_OSInitialisation(void); + + +#endif + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c new file mode 100644 index 0000000..e1d18cc --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.c @@ -0,0 +1,197 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_packedtags2.h" +#include "yportenv.h" +#include "yaffs_trace.h" + +/* This code packs a set of extended tags into a binary structure for + * NAND storage + */ + +/* Some of the information is "extra" struff which can be packed in to + * speed scanning + * This is defined by having the EXTRA_HEADER_INFO_FLAG set. + */ + +/* Extra flags applied to chunk_id */ + +#define EXTRA_HEADER_INFO_FLAG 0x80000000 +#define EXTRA_SHRINK_FLAG 0x40000000 +#define EXTRA_SHADOWS_FLAG 0x20000000 +#define EXTRA_SPARE_FLAGS 0x10000000 + +#define ALL_EXTRA_FLAGS 0xf0000000 + +/* Also, the top 4 bits of the object Id are set to the object type. */ +#define EXTRA_OBJECT_TYPE_SHIFT (28) +#define EXTRA_OBJECT_TYPE_MASK ((0x0f) << EXTRA_OBJECT_TYPE_SHIFT) + +static void yaffs_dump_packed_tags2_tags_only( + const struct yaffs_packed_tags2_tags_only *ptt) +{ + yaffs_trace(YAFFS_TRACE_MTD, + "packed tags obj %d chunk %d byte %d seq %d", + ptt->obj_id, ptt->chunk_id, ptt->n_bytes, ptt->seq_number); +} + +static void yaffs_dump_packed_tags2(const struct yaffs_packed_tags2 *pt) +{ + yaffs_dump_packed_tags2_tags_only(&pt->t); +} + +static void yaffs_dump_tags2(const struct yaffs_ext_tags *t) +{ + yaffs_trace(YAFFS_TRACE_MTD, + "ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d", + t->ecc_result, t->block_bad, t->chunk_used, t->obj_id, + t->chunk_id, t->n_bytes, t->is_deleted, t->serial_number, + t->seq_number); + +} + +static int yaffs_check_tags_extra_packable(const struct yaffs_ext_tags *t) +{ + if (t->chunk_id != 0 || !t->extra_available) + return 0; + + /* Check if the file size is too long to store */ + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE && + (t->extra_file_size >> 31) != 0) + return 0; + return 1; +} + +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *ptt, + const struct yaffs_ext_tags *t) +{ + ptt->chunk_id = t->chunk_id; + ptt->seq_number = t->seq_number; + ptt->n_bytes = t->n_bytes; + ptt->obj_id = t->obj_id; + + /* Only store extra tags for object headers. + * If it is a file then only store if the file size is short\ + * enough to fit. + */ + if (yaffs_check_tags_extra_packable(t)) { + /* Store the extra header info instead */ + /* We save the parent object in the chunk_id */ + ptt->chunk_id = EXTRA_HEADER_INFO_FLAG | t->extra_parent_id; + if (t->extra_is_shrink) + ptt->chunk_id |= EXTRA_SHRINK_FLAG; + if (t->extra_shadows) + ptt->chunk_id |= EXTRA_SHADOWS_FLAG; + + ptt->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; + ptt->obj_id |= (t->extra_obj_type << EXTRA_OBJECT_TYPE_SHIFT); + + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) + ptt->n_bytes = t->extra_equiv_id; + else if (t->extra_obj_type == YAFFS_OBJECT_TYPE_FILE) + ptt->n_bytes = (unsigned) t->extra_file_size; + else + ptt->n_bytes = 0; + } + + yaffs_dump_packed_tags2_tags_only(ptt); + yaffs_dump_tags2(t); +} + +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, + const struct yaffs_ext_tags *t, int tags_ecc) +{ + yaffs_pack_tags2_tags_only(&pt->t, t); + + if (tags_ecc) + yaffs_ecc_calc_other((unsigned char *)&pt->t, + sizeof(struct yaffs_packed_tags2_tags_only), + &pt->ecc); +} + +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, + struct yaffs_packed_tags2_tags_only *ptt) +{ + memset(t, 0, sizeof(struct yaffs_ext_tags)); + + if (ptt->seq_number == 0xffffffff) + return; + + t->block_bad = 0; + t->chunk_used = 1; + t->obj_id = ptt->obj_id; + t->chunk_id = ptt->chunk_id; + t->n_bytes = ptt->n_bytes; + t->is_deleted = 0; + t->serial_number = 0; + t->seq_number = ptt->seq_number; + + /* Do extra header info stuff */ + if (ptt->chunk_id & EXTRA_HEADER_INFO_FLAG) { + t->chunk_id = 0; + t->n_bytes = 0; + + t->extra_available = 1; + t->extra_parent_id = ptt->chunk_id & (~(ALL_EXTRA_FLAGS)); + t->extra_is_shrink = ptt->chunk_id & EXTRA_SHRINK_FLAG ? 1 : 0; + t->extra_shadows = ptt->chunk_id & EXTRA_SHADOWS_FLAG ? 1 : 0; + t->extra_obj_type = ptt->obj_id >> EXTRA_OBJECT_TYPE_SHIFT; + t->obj_id &= ~EXTRA_OBJECT_TYPE_MASK; + + if (t->extra_obj_type == YAFFS_OBJECT_TYPE_HARDLINK) + t->extra_equiv_id = ptt->n_bytes; + else + t->extra_file_size = ptt->n_bytes; + } + yaffs_dump_packed_tags2_tags_only(ptt); + yaffs_dump_tags2(t); +} + +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, + int tags_ecc) +{ + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + + if (pt->t.seq_number != 0xffffffff && tags_ecc) { + /* Chunk is in use and we need to do ECC */ + + struct yaffs_ecc_other ecc; + int result; + yaffs_ecc_calc_other((unsigned char *)&pt->t, + sizeof(struct yaffs_packed_tags2_tags_only), + &ecc); + result = + yaffs_ecc_correct_other((unsigned char *)&pt->t, + sizeof(struct yaffs_packed_tags2_tags_only), + &pt->ecc, &ecc); + switch (result) { + case 0: + ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + break; + case 1: + ecc_result = YAFFS_ECC_RESULT_FIXED; + break; + case -1: + ecc_result = YAFFS_ECC_RESULT_UNFIXED; + break; + default: + ecc_result = YAFFS_ECC_RESULT_UNKNOWN; + } + } + yaffs_unpack_tags2_tags_only(t, &pt->t); + + t->ecc_result = ecc_result; + + yaffs_dump_packed_tags2(pt); + yaffs_dump_tags2(t); +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h new file mode 100644 index 0000000..675e719 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_packedtags2.h @@ -0,0 +1,47 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* This is used to pack YAFFS2 tags, not YAFFS1tags. */ + +#ifndef __YAFFS_PACKEDTAGS2_H__ +#define __YAFFS_PACKEDTAGS2_H__ + +#include "yaffs_guts.h" +#include "yaffs_ecc.h" + +struct yaffs_packed_tags2_tags_only { + unsigned seq_number; + unsigned obj_id; + unsigned chunk_id; + unsigned n_bytes; +}; + +struct yaffs_packed_tags2 { + struct yaffs_packed_tags2_tags_only t; + struct yaffs_ecc_other ecc; +}; + +/* Full packed tags with ECC, used for oob tags */ +void yaffs_pack_tags2(struct yaffs_packed_tags2 *pt, + const struct yaffs_ext_tags *t, int tags_ecc); +void yaffs_unpack_tags2(struct yaffs_ext_tags *t, struct yaffs_packed_tags2 *pt, + int tags_ecc); + +/* Only the tags part (no ECC for use with inband tags */ +void yaffs_pack_tags2_tags_only(struct yaffs_packed_tags2_tags_only *pt, + const struct yaffs_ext_tags *t); +void yaffs_unpack_tags2_tags_only(struct yaffs_ext_tags *t, + struct yaffs_packed_tags2_tags_only *pt); +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c new file mode 100644 index 0000000..afd1ffa --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_qsort.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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 University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 "yportenv.h" +/* #include <linux/string.h> */ + +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) do { \ + long i = (n) / sizeof(TYPE); \ + register TYPE *pi = (TYPE *) (parmi); \ + register TYPE *pj = (TYPE *) (parmj); \ + do { \ + register TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} while (0) + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1; + +static inline void +swapfunc(char *a, char *b, int n, int swaptype) +{ + if (swaptype <= 1) + swapcode(long, a, b, n); + else + swapcode(char, a, b, n); +} + +#define yswap(a, b) do { \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype); \ +} while (0) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +static inline char * +med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *)) +{ + return cmp(a, b) < 0 ? + (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a)) + : (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c)); +} + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +void +yaffs_qsort(void *aa, size_t n, size_t es, + int (*cmp)(const void *, const void *)) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + int d, r, swaptype, swap_cnt; + register char *a = aa; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + yswap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = (char *)a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp); + pm = med3(pm - d, pm, pm + d, cmp); + pn = med3(pn - 2 * d, pn - d, pn, cmp); + } + pm = med3(pl, pm, pn, cmp); + } + yswap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = cmp(pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + yswap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = cmp(pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + yswap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + yswap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es) + for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0; + pl -= es) + yswap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min((long)(pd - pc), (long)(pn - pd - es)); + vecswap(pb, pn - r, r); + r = pb - pa; + if (r > es) + yaffs_qsort(a, r / es, es, cmp); + r = pd - pc; + if (r > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* yaffs_qsort(pn - r, r / es, es, cmp);*/ +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c new file mode 100644 index 0000000..6f3c783 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.c @@ -0,0 +1,313 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +/* Summaries write the useful part of the tags for the chunks in a block into an + * an array which is written to the last n chunks of the block. + * Reading the summaries gives all the tags for the block in one read. Much + * faster. + * + * Chunks holding summaries are marked with tags making it look like + * they are part of a fake file. + * + * The summary could also be used during gc. + * + */ + +#include "yaffs_summary.h" +#include "yaffs_packedtags2.h" +#include "yaffs_nand.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_bitmap.h" + +/* + * The summary is built up in an array of summary tags. + * This gets written to the last one or two (maybe more) chunks in a block. + * A summary header is written as the first part of each chunk of summary data. + * The summary header must match or the summary is rejected. + */ + +/* Summary tags don't need the sequence number because that is redundant. */ +struct yaffs_summary_tags { + unsigned obj_id; + unsigned chunk_id; + unsigned n_bytes; +}; + +/* Summary header */ +struct yaffs_summary_header { + unsigned version; /* Must match current version */ + unsigned block; /* Must be this block */ + unsigned seq; /* Must be this sequence number */ + unsigned sum; /* Just add up all the bytes in the tags */ +}; + + +static void yaffs_summary_clear(struct yaffs_dev *dev) +{ + if (!dev->sum_tags) + return; + memset(dev->sum_tags, 0, dev->chunks_per_summary * + sizeof(struct yaffs_summary_tags)); +} + + +void yaffs_summary_deinit(struct yaffs_dev *dev) +{ + kfree(dev->sum_tags); + dev->sum_tags = NULL; + kfree(dev->gc_sum_tags); + dev->gc_sum_tags = NULL; + dev->chunks_per_summary = 0; +} + +int yaffs_summary_init(struct yaffs_dev *dev) +{ + int sum_bytes; + int chunks_used; /* Number of chunks used by summary */ + int sum_tags_bytes; + + sum_bytes = dev->param.chunks_per_block * + sizeof(struct yaffs_summary_tags); + + chunks_used = (sum_bytes + dev->data_bytes_per_chunk - 1)/ + (dev->data_bytes_per_chunk - + sizeof(struct yaffs_summary_header)); + + dev->chunks_per_summary = dev->param.chunks_per_block - chunks_used; + sum_tags_bytes = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + dev->sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); + dev->gc_sum_tags = kmalloc(sum_tags_bytes, GFP_NOFS); + if (!dev->sum_tags || !dev->gc_sum_tags) { + yaffs_summary_deinit(dev); + return YAFFS_FAIL; + } + + yaffs_summary_clear(dev); + + return YAFFS_OK; +} + +static unsigned yaffs_summary_sum(struct yaffs_dev *dev) +{ + u8 *sum_buffer = (u8 *)dev->sum_tags; + int i; + unsigned sum = 0; + + i = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + while (i > 0) { + sum += *sum_buffer; + sum_buffer++; + i--; + } + + return sum; +} + +static int yaffs_summary_write(struct yaffs_dev *dev, int blk) +{ + struct yaffs_ext_tags tags; + u8 *buffer; + u8 *sum_buffer = (u8 *)dev->sum_tags; + int n_bytes; + int chunk_in_nand; + int chunk_in_block; + int result; + int this_tx; + struct yaffs_summary_header hdr; + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); + + buffer = yaffs_get_temp_buffer(dev); + n_bytes = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + memset(&tags, 0, sizeof(struct yaffs_ext_tags)); + tags.obj_id = YAFFS_OBJECTID_SUMMARY; + tags.chunk_id = 1; + chunk_in_block = dev->chunks_per_summary; + chunk_in_nand = dev->alloc_block * dev->param.chunks_per_block + + dev->chunks_per_summary; + hdr.version = YAFFS_SUMMARY_VERSION; + hdr.block = blk; + hdr.seq = bi->seq_number; + hdr.sum = yaffs_summary_sum(dev); + + do { + this_tx = n_bytes; + if (this_tx > sum_bytes_per_chunk) + this_tx = sum_bytes_per_chunk; + memcpy(buffer, &hdr, sizeof(hdr)); + memcpy(buffer + sizeof(hdr), sum_buffer, this_tx); + tags.n_bytes = this_tx + sizeof(hdr); + result = yaffs_wr_chunk_tags_nand(dev, chunk_in_nand, + buffer, &tags); + + if (result != YAFFS_OK) + break; + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + dev->n_free_chunks--; + + n_bytes -= this_tx; + sum_buffer += this_tx; + chunk_in_nand++; + chunk_in_block++; + tags.chunk_id++; + } while (result == YAFFS_OK && n_bytes > 0); + yaffs_release_temp_buffer(dev, buffer); + + + if (result == YAFFS_OK) + bi->has_summary = 1; + + + return result; +} + +int yaffs_summary_read(struct yaffs_dev *dev, + struct yaffs_summary_tags *st, + int blk) +{ + struct yaffs_ext_tags tags; + u8 *buffer; + u8 *sum_buffer = (u8 *)st; + int n_bytes; + int chunk_id; + int chunk_in_nand; + int chunk_in_block; + int result; + int this_tx; + struct yaffs_summary_header hdr; + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); + int sum_bytes_per_chunk = dev->data_bytes_per_chunk - sizeof(hdr); + int sum_tags_bytes; + + sum_tags_bytes = sizeof(struct yaffs_summary_tags) * + dev->chunks_per_summary; + buffer = yaffs_get_temp_buffer(dev); + n_bytes = sizeof(struct yaffs_summary_tags) * dev->chunks_per_summary; + chunk_in_block = dev->chunks_per_summary; + chunk_in_nand = blk * dev->param.chunks_per_block + + dev->chunks_per_summary; + chunk_id = 1; + do { + this_tx = n_bytes; + if (this_tx > sum_bytes_per_chunk) + this_tx = sum_bytes_per_chunk; + result = yaffs_rd_chunk_tags_nand(dev, chunk_in_nand, + buffer, &tags); + + if (tags.chunk_id != chunk_id || + tags.obj_id != YAFFS_OBJECTID_SUMMARY || + tags.chunk_used == 0 || + tags.ecc_result > YAFFS_ECC_RESULT_FIXED || + tags.n_bytes != (this_tx + sizeof(hdr))) + result = YAFFS_FAIL; + if (result != YAFFS_OK) + break; + + if (st == dev->sum_tags) { + /* If we're scanning then update the block info */ + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + } + memcpy(&hdr, buffer, sizeof(hdr)); + memcpy(sum_buffer, buffer + sizeof(hdr), this_tx); + n_bytes -= this_tx; + sum_buffer += this_tx; + chunk_in_nand++; + chunk_in_block++; + chunk_id++; + } while (result == YAFFS_OK && n_bytes > 0); + yaffs_release_temp_buffer(dev, buffer); + + if (result == YAFFS_OK) { + /* Verify header */ + if (hdr.version != YAFFS_SUMMARY_VERSION || + hdr.block != blk || + hdr.seq != bi->seq_number || + hdr.sum != yaffs_summary_sum(dev)) + result = YAFFS_FAIL; + } + + if (st == dev->sum_tags && result == YAFFS_OK) + bi->has_summary = 1; + + return result; +} + +int yaffs_summary_add(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_nand) +{ + struct yaffs_packed_tags2_tags_only tags_only; + struct yaffs_summary_tags *sum_tags; + int block_in_nand = chunk_in_nand / dev->param.chunks_per_block; + int chunk_in_block = chunk_in_nand % dev->param.chunks_per_block; + + if (!dev->sum_tags) + return YAFFS_OK; + + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { + yaffs_pack_tags2_tags_only(&tags_only, tags); + sum_tags = &dev->sum_tags[chunk_in_block]; + sum_tags->chunk_id = tags_only.chunk_id; + sum_tags->n_bytes = tags_only.n_bytes; + sum_tags->obj_id = tags_only.obj_id; + + if (chunk_in_block == dev->chunks_per_summary - 1) { + /* Time to write out the summary */ + yaffs_summary_write(dev, block_in_nand); + yaffs_summary_clear(dev); + yaffs_skip_rest_of_block(dev); + } + } + return YAFFS_OK; +} + +int yaffs_summary_fetch(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_block) +{ + struct yaffs_packed_tags2_tags_only tags_only; + struct yaffs_summary_tags *sum_tags; + if (chunk_in_block >= 0 && chunk_in_block < dev->chunks_per_summary) { + sum_tags = &dev->sum_tags[chunk_in_block]; + tags_only.chunk_id = sum_tags->chunk_id; + tags_only.n_bytes = sum_tags->n_bytes; + tags_only.obj_id = sum_tags->obj_id; + yaffs_unpack_tags2_tags_only(tags, &tags_only); + return YAFFS_OK; + } + return YAFFS_FAIL; +} + +void yaffs_summary_gc(struct yaffs_dev *dev, int blk) +{ + struct yaffs_block_info *bi = yaffs_get_block_info(dev, blk); + int i; + + if (!bi->has_summary) + return; + + for (i = dev->chunks_per_summary; + i < dev->param.chunks_per_block; + i++) { + if (yaffs_check_chunk_bit(dev, blk, i)) { + yaffs_clear_chunk_bit(dev, blk, i); + bi->pages_in_use--; + dev->n_free_chunks++; + } + } +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h new file mode 100644 index 0000000..be141d0 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_summary.h @@ -0,0 +1,37 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_SUMMARY_H__ +#define __YAFFS_SUMMARY_H__ + +#include "yaffs_packedtags2.h" + + +int yaffs_summary_init(struct yaffs_dev *dev); +void yaffs_summary_deinit(struct yaffs_dev *dev); + +int yaffs_summary_add(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_block); +int yaffs_summary_fetch(struct yaffs_dev *dev, + struct yaffs_ext_tags *tags, + int chunk_in_block); +int yaffs_summary_read(struct yaffs_dev *dev, + struct yaffs_summary_tags *st, + int blk); +void yaffs_summary_gc(struct yaffs_dev *dev, int blk); + + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c new file mode 100644 index 0000000..32ba11f --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.c @@ -0,0 +1,407 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_guts.h" +#include "yaffs_tagscompat.h" +#include "yaffs_ecc.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_trace.h" + +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk); + + +/********** Tags ECC calculations *********/ + +static void yaffs_calc_ecc(const u8 *data, struct yaffs_spare *spare) +{ + yaffs_ecc_calc(data, spare->ecc1); + yaffs_ecc_calc(&data[256], spare->ecc2); +} + +void yaffs_calc_tags_ecc(struct yaffs_tags *tags) +{ + /* Calculate an ecc */ + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; + unsigned i, j; + unsigned ecc = 0; + unsigned bit = 0; + + tags->ecc = 0; + + for (i = 0; i < 8; i++) { + for (j = 1; j & 0xff; j <<= 1) { + bit++; + if (b[i] & j) + ecc ^= bit; + } + } + tags->ecc = ecc; +} + +int yaffs_check_tags_ecc(struct yaffs_tags *tags) +{ + unsigned ecc = tags->ecc; + + yaffs_calc_tags_ecc(tags); + + ecc ^= tags->ecc; + + if (ecc && ecc <= 64) { + /* TODO: Handle the failure better. Retire? */ + unsigned char *b = ((union yaffs_tags_union *)tags)->as_bytes; + + ecc--; + + b[ecc / 8] ^= (1 << (ecc & 7)); + + /* Now recvalc the ecc */ + yaffs_calc_tags_ecc(tags); + + return 1; /* recovered error */ + } else if (ecc) { + /* Wierd ecc failure value */ + /* TODO Need to do somethiong here */ + return -1; /* unrecovered error */ + } + return 0; +} + +/********** Tags **********/ + +static void yaffs_load_tags_to_spare(struct yaffs_spare *spare_ptr, + struct yaffs_tags *tags_ptr) +{ + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; + + yaffs_calc_tags_ecc(tags_ptr); + + spare_ptr->tb0 = tu->as_bytes[0]; + spare_ptr->tb1 = tu->as_bytes[1]; + spare_ptr->tb2 = tu->as_bytes[2]; + spare_ptr->tb3 = tu->as_bytes[3]; + spare_ptr->tb4 = tu->as_bytes[4]; + spare_ptr->tb5 = tu->as_bytes[5]; + spare_ptr->tb6 = tu->as_bytes[6]; + spare_ptr->tb7 = tu->as_bytes[7]; +} + +static void yaffs_get_tags_from_spare(struct yaffs_dev *dev, + struct yaffs_spare *spare_ptr, + struct yaffs_tags *tags_ptr) +{ + union yaffs_tags_union *tu = (union yaffs_tags_union *)tags_ptr; + int result; + + tu->as_bytes[0] = spare_ptr->tb0; + tu->as_bytes[1] = spare_ptr->tb1; + tu->as_bytes[2] = spare_ptr->tb2; + tu->as_bytes[3] = spare_ptr->tb3; + tu->as_bytes[4] = spare_ptr->tb4; + tu->as_bytes[5] = spare_ptr->tb5; + tu->as_bytes[6] = spare_ptr->tb6; + tu->as_bytes[7] = spare_ptr->tb7; + + result = yaffs_check_tags_ecc(tags_ptr); + if (result > 0) + dev->n_tags_ecc_fixed++; + else if (result < 0) + dev->n_tags_ecc_unfixed++; +} + +static void yaffs_spare_init(struct yaffs_spare *spare) +{ + memset(spare, 0xff, sizeof(struct yaffs_spare)); +} + +static int yaffs_wr_nand(struct yaffs_dev *dev, + int nand_chunk, const u8 *data, + struct yaffs_spare *spare) +{ + if (nand_chunk < dev->param.start_block * dev->param.chunks_per_block) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>> yaffs chunk %d is not valid", + nand_chunk); + return YAFFS_FAIL; + } + + return dev->param.write_chunk_fn(dev, nand_chunk, data, spare); +} + +static int yaffs_rd_chunk_nand(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, + struct yaffs_spare *spare, + enum yaffs_ecc_result *ecc_result, + int correct_errors) +{ + int ret_val; + struct yaffs_spare local_spare; + + if (!spare) { + /* If we don't have a real spare, then we use a local one. */ + /* Need this for the calculation of the ecc */ + spare = &local_spare; + } + + if (!dev->param.use_nand_ecc) { + ret_val = + dev->param.read_chunk_fn(dev, nand_chunk, data, spare); + if (data && correct_errors) { + /* Do ECC correction */ + /* Todo handle any errors */ + int ecc_result1, ecc_result2; + u8 calc_ecc[3]; + + yaffs_ecc_calc(data, calc_ecc); + ecc_result1 = + yaffs_ecc_correct(data, spare->ecc1, calc_ecc); + yaffs_ecc_calc(&data[256], calc_ecc); + ecc_result2 = + yaffs_ecc_correct(&data[256], spare->ecc2, + calc_ecc); + + if (ecc_result1 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error fix performed on chunk %d:0", + nand_chunk); + dev->n_ecc_fixed++; + } else if (ecc_result1 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error unfixed on chunk %d:0", + nand_chunk); + dev->n_ecc_unfixed++; + } + + if (ecc_result2 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error fix performed on chunk %d:1", + nand_chunk); + dev->n_ecc_fixed++; + } else if (ecc_result2 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>yaffs ecc error unfixed on chunk %d:1", + nand_chunk); + dev->n_ecc_unfixed++; + } + + if (ecc_result1 || ecc_result2) { + /* We had a data problem on this page */ + yaffs_handle_rd_data_error(dev, nand_chunk); + } + + if (ecc_result1 < 0 || ecc_result2 < 0) + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; + else if (ecc_result1 > 0 || ecc_result2 > 0) + *ecc_result = YAFFS_ECC_RESULT_FIXED; + else + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + } + } else { + /* Must allocate enough memory for spare+2*sizeof(int) */ + /* for ecc results from device. */ + struct yaffs_nand_spare nspare; + + memset(&nspare, 0, sizeof(nspare)); + + ret_val = dev->param.read_chunk_fn(dev, nand_chunk, data, + (struct yaffs_spare *) + &nspare); + memcpy(spare, &nspare, sizeof(struct yaffs_spare)); + if (data && correct_errors) { + if (nspare.eccres1 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>mtd ecc error fix performed on chunk %d:0", + nand_chunk); + } else if (nspare.eccres1 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>mtd ecc error unfixed on chunk %d:0", + nand_chunk); + } + + if (nspare.eccres2 > 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>mtd ecc error fix performed on chunk %d:1", + nand_chunk); + } else if (nspare.eccres2 < 0) { + yaffs_trace(YAFFS_TRACE_ERROR, + "**>>mtd ecc error unfixed on chunk %d:1", + nand_chunk); + } + + if (nspare.eccres1 || nspare.eccres2) { + /* We had a data problem on this page */ + yaffs_handle_rd_data_error(dev, nand_chunk); + } + + if (nspare.eccres1 < 0 || nspare.eccres2 < 0) + *ecc_result = YAFFS_ECC_RESULT_UNFIXED; + else if (nspare.eccres1 > 0 || nspare.eccres2 > 0) + *ecc_result = YAFFS_ECC_RESULT_FIXED; + else + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + + } + } + return ret_val; +} + +/* + * Functions for robustisizing + */ + +static void yaffs_handle_rd_data_error(struct yaffs_dev *dev, int nand_chunk) +{ + int flash_block = nand_chunk / dev->param.chunks_per_block; + + /* Mark the block for retirement */ + yaffs_get_block_info(dev, flash_block + dev->block_offset)-> + needs_retiring = 1; + yaffs_trace(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS, + "**>>Block %d marked for retirement", + flash_block); + + /* TODO: + * Just do a garbage collection on the affected block + * then retire the block + * NB recursion + */ +} + +int yaffs_tags_compat_wr(struct yaffs_dev *dev, + int nand_chunk, + const u8 *data, const struct yaffs_ext_tags *ext_tags) +{ + struct yaffs_spare spare; + struct yaffs_tags tags; + + yaffs_spare_init(&spare); + + if (ext_tags->is_deleted) + spare.page_status = 0; + else { + tags.obj_id = ext_tags->obj_id; + tags.chunk_id = ext_tags->chunk_id; + + tags.n_bytes_lsb = ext_tags->n_bytes & (1024 - 1); + + if (dev->data_bytes_per_chunk >= 1024) + tags.n_bytes_msb = (ext_tags->n_bytes >> 10) & 3; + else + tags.n_bytes_msb = 3; + + tags.serial_number = ext_tags->serial_number; + + if (!dev->param.use_nand_ecc && data) + yaffs_calc_ecc(data, &spare); + + yaffs_load_tags_to_spare(&spare, &tags); + } + return yaffs_wr_nand(dev, nand_chunk, data, &spare); +} + +int yaffs_tags_compat_rd(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, struct yaffs_ext_tags *ext_tags) +{ + struct yaffs_spare spare; + struct yaffs_tags tags; + enum yaffs_ecc_result ecc_result = YAFFS_ECC_RESULT_UNKNOWN; + static struct yaffs_spare spare_ff; + static int init; + int deleted; + + if (!init) { + memset(&spare_ff, 0xff, sizeof(spare_ff)); + init = 1; + } + + if (!yaffs_rd_chunk_nand(dev, nand_chunk, + data, &spare, &ecc_result, 1)) + return YAFFS_FAIL; + + /* ext_tags may be NULL */ + if (!ext_tags) + return YAFFS_OK; + + deleted = (hweight8(spare.page_status) < 7) ? 1 : 0; + + ext_tags->is_deleted = deleted; + ext_tags->ecc_result = ecc_result; + ext_tags->block_bad = 0; /* We're reading it */ + /* therefore it is not a bad block */ + ext_tags->chunk_used = + memcmp(&spare_ff, &spare, sizeof(spare_ff)) ? 1 : 0; + + if (ext_tags->chunk_used) { + yaffs_get_tags_from_spare(dev, &spare, &tags); + ext_tags->obj_id = tags.obj_id; + ext_tags->chunk_id = tags.chunk_id; + ext_tags->n_bytes = tags.n_bytes_lsb; + + if (dev->data_bytes_per_chunk >= 1024) + ext_tags->n_bytes |= + (((unsigned)tags.n_bytes_msb) << 10); + + ext_tags->serial_number = tags.serial_number; + } + + return YAFFS_OK; +} + +int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int flash_block) +{ + struct yaffs_spare spare; + + memset(&spare, 0xff, sizeof(struct yaffs_spare)); + + spare.block_status = 'Y'; + + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block, NULL, + &spare); + yaffs_wr_nand(dev, flash_block * dev->param.chunks_per_block + 1, + NULL, &spare); + + return YAFFS_OK; +} + +int yaffs_tags_compat_query_block(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 *seq_number) +{ + struct yaffs_spare spare0, spare1; + static struct yaffs_spare spare_ff; + static int init; + enum yaffs_ecc_result dummy; + + if (!init) { + memset(&spare_ff, 0xff, sizeof(spare_ff)); + init = 1; + } + + *seq_number = 0; + + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block, NULL, + &spare0, &dummy, 1); + yaffs_rd_chunk_nand(dev, block_no * dev->param.chunks_per_block + 1, + NULL, &spare1, &dummy, 1); + + if (hweight8(spare0.block_status & spare1.block_status) < 7) + *state = YAFFS_BLOCK_STATE_DEAD; + else if (memcmp(&spare_ff, &spare0, sizeof(spare_ff)) == 0) + *state = YAFFS_BLOCK_STATE_EMPTY; + else + *state = YAFFS_BLOCK_STATE_NEEDS_SCAN; + + return YAFFS_OK; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h new file mode 100644 index 0000000..b3c6655 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_tagscompat.h @@ -0,0 +1,36 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_TAGSCOMPAT_H__ +#define __YAFFS_TAGSCOMPAT_H__ + +#include "yaffs_guts.h" +int yaffs_tags_compat_wr(struct yaffs_dev *dev, + int nand_chunk, + const u8 *data, const struct yaffs_ext_tags *tags); +int yaffs_tags_compat_rd(struct yaffs_dev *dev, + int nand_chunk, + u8 *data, struct yaffs_ext_tags *tags); +int yaffs_tags_compat_mark_bad(struct yaffs_dev *dev, int block_no); +int yaffs_tags_compat_query_block(struct yaffs_dev *dev, + int block_no, + enum yaffs_block_state *state, + u32 *seq_number); + +void yaffs_calc_tags_ecc(struct yaffs_tags *tags); +int yaffs_check_tags_ecc(struct yaffs_tags *tags); +int yaffs_count_bits(u8 byte); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h new file mode 100644 index 0000000..fd26054 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_trace.h @@ -0,0 +1,57 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YTRACE_H__ +#define __YTRACE_H__ + +extern unsigned int yaffs_trace_mask; +extern unsigned int yaffs_wr_attempts; + +/* + * Tracing flags. + * The flags masked in YAFFS_TRACE_ALWAYS are always traced. + */ + +#define YAFFS_TRACE_OS 0x00000002 +#define YAFFS_TRACE_ALLOCATE 0x00000004 +#define YAFFS_TRACE_SCAN 0x00000008 +#define YAFFS_TRACE_BAD_BLOCKS 0x00000010 +#define YAFFS_TRACE_ERASE 0x00000020 +#define YAFFS_TRACE_GC 0x00000040 +#define YAFFS_TRACE_WRITE 0x00000080 +#define YAFFS_TRACE_TRACING 0x00000100 +#define YAFFS_TRACE_DELETION 0x00000200 +#define YAFFS_TRACE_BUFFERS 0x00000400 +#define YAFFS_TRACE_NANDACCESS 0x00000800 +#define YAFFS_TRACE_GC_DETAIL 0x00001000 +#define YAFFS_TRACE_SCAN_DEBUG 0x00002000 +#define YAFFS_TRACE_MTD 0x00004000 +#define YAFFS_TRACE_CHECKPOINT 0x00008000 + +#define YAFFS_TRACE_VERIFY 0x00010000 +#define YAFFS_TRACE_VERIFY_NAND 0x00020000 +#define YAFFS_TRACE_VERIFY_FULL 0x00040000 +#define YAFFS_TRACE_VERIFY_ALL 0x000f0000 + +#define YAFFS_TRACE_SYNC 0x00100000 +#define YAFFS_TRACE_BACKGROUND 0x00200000 +#define YAFFS_TRACE_LOCK 0x00400000 +#define YAFFS_TRACE_MOUNT 0x00800000 + +#define YAFFS_TRACE_ERROR 0x40000000 +#define YAFFS_TRACE_BUG 0x80000000 +#define YAFFS_TRACE_ALWAYS 0xf0000000 + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c new file mode 100644 index 0000000..e8f2f0a --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.c @@ -0,0 +1,529 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_verify.h" +#include "yaffs_trace.h" +#include "yaffs_bitmap.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_nand.h" + +int yaffs_skip_verification(struct yaffs_dev *dev) +{ + (void) dev; + return !(yaffs_trace_mask & + (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL)); +} + +static int yaffs_skip_full_verification(struct yaffs_dev *dev) +{ + (void) dev; + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_FULL)); +} + +static int yaffs_skip_nand_verification(struct yaffs_dev *dev) +{ + (void) dev; + return !(yaffs_trace_mask & (YAFFS_TRACE_VERIFY_NAND)); +} + +static const char * const block_state_name[] = { + "Unknown", + "Needs scan", + "Scanning", + "Empty", + "Allocating", + "Full", + "Dirty", + "Checkpoint", + "Collecting", + "Dead" +}; + +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, int n) +{ + int actually_used; + int in_use; + + if (yaffs_skip_verification(dev)) + return; + + /* Report illegal runtime states */ + if (bi->block_state >= YAFFS_NUMBER_OF_BLOCK_STATES) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has undefined state %d", + n, bi->block_state); + + switch (bi->block_state) { + case YAFFS_BLOCK_STATE_UNKNOWN: + case YAFFS_BLOCK_STATE_SCANNING: + case YAFFS_BLOCK_STATE_NEEDS_SCAN: + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has bad run-state %s", + n, block_state_name[bi->block_state]); + } + + /* Check pages in use and soft deletions are legal */ + + actually_used = bi->pages_in_use - bi->soft_del_pages; + + if (bi->pages_in_use < 0 || + bi->pages_in_use > dev->param.chunks_per_block || + bi->soft_del_pages < 0 || + bi->soft_del_pages > dev->param.chunks_per_block || + actually_used < 0 || actually_used > dev->param.chunks_per_block) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has illegal values pages_in_used %d soft_del_pages %d", + n, bi->pages_in_use, bi->soft_del_pages); + + /* Check chunk bitmap legal */ + in_use = yaffs_count_chunk_bits(dev, n); + if (in_use != bi->pages_in_use) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Block %d has inconsistent values pages_in_use %d counted chunk bits %d", + n, bi->pages_in_use, in_use); +} + +void yaffs_verify_collected_blk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, int n) +{ + yaffs_verify_blk(dev, bi, n); + + /* After collection the block should be in the erased state */ + + if (bi->block_state != YAFFS_BLOCK_STATE_COLLECTING && + bi->block_state != YAFFS_BLOCK_STATE_EMPTY) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Block %d is in state %d after gc, should be erased", + n, bi->block_state); + } +} + +void yaffs_verify_blocks(struct yaffs_dev *dev) +{ + int i; + int state_count[YAFFS_NUMBER_OF_BLOCK_STATES]; + int illegal_states = 0; + + if (yaffs_skip_verification(dev)) + return; + + memset(state_count, 0, sizeof(state_count)); + + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + struct yaffs_block_info *bi = yaffs_get_block_info(dev, i); + yaffs_verify_blk(dev, bi, i); + + if (bi->block_state < YAFFS_NUMBER_OF_BLOCK_STATES) + state_count[bi->block_state]++; + else + illegal_states++; + } + + yaffs_trace(YAFFS_TRACE_VERIFY, "Block summary"); + + yaffs_trace(YAFFS_TRACE_VERIFY, + "%d blocks have illegal states", + illegal_states); + if (state_count[YAFFS_BLOCK_STATE_ALLOCATING] > 1) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Too many allocating blocks"); + + for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++) + yaffs_trace(YAFFS_TRACE_VERIFY, + "%s %d blocks", + block_state_name[i], state_count[i]); + + if (dev->blocks_in_checkpt != state_count[YAFFS_BLOCK_STATE_CHECKPOINT]) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Checkpoint block count wrong dev %d count %d", + dev->blocks_in_checkpt, + state_count[YAFFS_BLOCK_STATE_CHECKPOINT]); + + if (dev->n_erased_blocks != state_count[YAFFS_BLOCK_STATE_EMPTY]) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Erased block count wrong dev %d count %d", + dev->n_erased_blocks, + state_count[YAFFS_BLOCK_STATE_EMPTY]); + + if (state_count[YAFFS_BLOCK_STATE_COLLECTING] > 1) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Too many collecting blocks %d (max is 1)", + state_count[YAFFS_BLOCK_STATE_COLLECTING]); +} + +/* + * Verify the object header. oh must be valid, but obj and tags may be NULL in + * which case those tests will not be performed. + */ +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, + struct yaffs_ext_tags *tags, int parent_check) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; + + if (!(tags && obj && oh)) { + yaffs_trace(YAFFS_TRACE_VERIFY, + "Verifying object header tags %p obj %p oh %p", + tags, obj, oh); + return; + } + + if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN || + oh->type > YAFFS_OBJECT_TYPE_MAX) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header type is illegal value 0x%x", + tags->obj_id, oh->type); + + if (tags->obj_id != obj->obj_id) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header mismatch obj_id %d", + tags->obj_id, obj->obj_id); + + /* + * Check that the object's parent ids match if parent_check requested. + * + * Tests do not apply to the root object. + */ + + if (parent_check && tags->obj_id > 1 && !obj->parent) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header mismatch parent_id %d obj->parent is NULL", + tags->obj_id, oh->parent_obj_id); + + if (parent_check && obj->parent && + oh->parent_obj_id != obj->parent->obj_id && + (oh->parent_obj_id != YAFFS_OBJECTID_UNLINKED || + obj->parent->obj_id != YAFFS_OBJECTID_DELETED)) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header mismatch parent_id %d parent_obj_id %d", + tags->obj_id, oh->parent_obj_id, + obj->parent->obj_id); + + if (tags->obj_id > 1 && oh->name[0] == 0) /* Null name */ + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header name is NULL", + obj->obj_id); + + if (tags->obj_id > 1 && ((u8) (oh->name[0])) == 0xff) /* Junk name */ + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d header name is 0xff", + obj->obj_id); +} + +void yaffs_verify_file(struct yaffs_obj *obj) +{ + u32 x; + int required_depth; + int actual_depth; + int last_chunk; + u32 offset_in_chunk; + u32 the_chunk; + + u32 i; + struct yaffs_dev *dev; + struct yaffs_ext_tags tags; + struct yaffs_tnode *tn; + u32 obj_id; + + if (!obj) + return; + + if (yaffs_skip_verification(obj->my_dev)) + return; + + dev = obj->my_dev; + obj_id = obj->obj_id; + + + /* Check file size is consistent with tnode depth */ + yaffs_addr_to_chunk(dev, obj->variant.file_variant.file_size, + &last_chunk, &offset_in_chunk); + last_chunk++; + x = last_chunk >> YAFFS_TNODES_LEVEL0_BITS; + required_depth = 0; + while (x > 0) { + x >>= YAFFS_TNODES_INTERNAL_BITS; + required_depth++; + } + + actual_depth = obj->variant.file_variant.top_level; + + /* Check that the chunks in the tnode tree are all correct. + * We do this by scanning through the tnode tree and + * checking the tags for every chunk match. + */ + + if (yaffs_skip_nand_verification(dev)) + return; + + for (i = 1; i <= last_chunk; i++) { + tn = yaffs_find_tnode_0(dev, &obj->variant.file_variant, i); + + if (!tn) + continue; + + the_chunk = yaffs_get_group_base(dev, tn, i); + if (the_chunk > 0) { + yaffs_rd_chunk_tags_nand(dev, the_chunk, NULL, + &tags); + if (tags.obj_id != obj_id || tags.chunk_id != i) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Object %d chunk_id %d NAND mismatch chunk %d tags (%d:%d)", + obj_id, i, the_chunk, + tags.obj_id, tags.chunk_id); + } + } +} + +void yaffs_verify_link(struct yaffs_obj *obj) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; + + /* Verify sane equivalent object */ +} + +void yaffs_verify_symlink(struct yaffs_obj *obj) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; + + /* Verify symlink string */ +} + +void yaffs_verify_special(struct yaffs_obj *obj) +{ + if (obj && yaffs_skip_verification(obj->my_dev)) + return; +} + +void yaffs_verify_obj(struct yaffs_obj *obj) +{ + struct yaffs_dev *dev; + u32 chunk_min; + u32 chunk_max; + u32 chunk_id_ok; + u32 chunk_in_range; + u32 chunk_wrongly_deleted; + u32 chunk_valid; + + if (!obj) + return; + + if (obj->being_created) + return; + + dev = obj->my_dev; + + if (yaffs_skip_verification(dev)) + return; + + /* Check sane object header chunk */ + + chunk_min = dev->internal_start_block * dev->param.chunks_per_block; + chunk_max = + (dev->internal_end_block + 1) * dev->param.chunks_per_block - 1; + + chunk_in_range = (((unsigned)(obj->hdr_chunk)) >= chunk_min && + ((unsigned)(obj->hdr_chunk)) <= chunk_max); + chunk_id_ok = chunk_in_range || (obj->hdr_chunk == 0); + chunk_valid = chunk_in_range && + yaffs_check_chunk_bit(dev, + obj->hdr_chunk / dev->param.chunks_per_block, + obj->hdr_chunk % dev->param.chunks_per_block); + chunk_wrongly_deleted = chunk_in_range && !chunk_valid; + + if (!obj->fake && (!chunk_id_ok || chunk_wrongly_deleted)) + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d has chunk_id %d %s %s", + obj->obj_id, obj->hdr_chunk, + chunk_id_ok ? "" : ",out of range", + chunk_wrongly_deleted ? ",marked as deleted" : ""); + + if (chunk_valid && !yaffs_skip_nand_verification(dev)) { + struct yaffs_ext_tags tags; + struct yaffs_obj_hdr *oh; + u8 *buffer = yaffs_get_temp_buffer(dev); + + oh = (struct yaffs_obj_hdr *)buffer; + + yaffs_rd_chunk_tags_nand(dev, obj->hdr_chunk, buffer, &tags); + + yaffs_verify_oh(obj, oh, &tags, 1); + + yaffs_release_temp_buffer(dev, buffer); + } + + /* Verify it has a parent */ + if (obj && !obj->fake && (!obj->parent || obj->parent->my_dev != dev)) { + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d has parent pointer %p which does not look like an object", + obj->obj_id, obj->parent); + } + + /* Verify parent is a directory */ + if (obj->parent && + obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d's parent is not a directory (type %d)", + obj->obj_id, obj->parent->variant_type); + } + + switch (obj->variant_type) { + case YAFFS_OBJECT_TYPE_FILE: + yaffs_verify_file(obj); + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + yaffs_verify_symlink(obj); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + yaffs_verify_dir(obj); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + yaffs_verify_link(obj); + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + yaffs_verify_special(obj); + break; + case YAFFS_OBJECT_TYPE_UNKNOWN: + default: + yaffs_trace(YAFFS_TRACE_VERIFY, + "Obj %d has illegaltype %d", + obj->obj_id, obj->variant_type); + break; + } +} + +void yaffs_verify_objects(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + int i; + struct list_head *lh; + + if (yaffs_skip_verification(dev)) + return; + + /* Iterate through the objects in each hash entry */ + + for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) { + list_for_each(lh, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link); + yaffs_verify_obj(obj); + } + } +} + +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj) +{ + struct list_head *lh; + struct yaffs_obj *list_obj; + int count = 0; + + if (!obj) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "No object to verify"); + BUG(); + return; + } + + if (yaffs_skip_verification(obj->my_dev)) + return; + + if (!obj->parent) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "Object does not have parent"); + BUG(); + return; + } + + if (obj->parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, "Parent is not directory"); + BUG(); + } + + /* Iterate through the objects in each hash entry */ + + list_for_each(lh, &obj->parent->variant.dir_variant.children) { + list_obj = list_entry(lh, struct yaffs_obj, siblings); + yaffs_verify_obj(list_obj); + if (obj == list_obj) + count++; + } + + if (count != 1) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Object in directory %d times", + count); + BUG(); + } +} + +void yaffs_verify_dir(struct yaffs_obj *directory) +{ + struct list_head *lh; + struct yaffs_obj *list_obj; + + if (!directory) { + BUG(); + return; + } + + if (yaffs_skip_full_verification(directory->my_dev)) + return; + + if (directory->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Directory has wrong type: %d", + directory->variant_type); + BUG(); + } + + /* Iterate through the objects in each hash entry */ + + list_for_each(lh, &directory->variant.dir_variant.children) { + list_obj = list_entry(lh, struct yaffs_obj, siblings); + if (list_obj->parent != directory) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Object in directory list has wrong parent %p", + list_obj->parent); + BUG(); + } + yaffs_verify_obj_in_dir(list_obj); + } +} + +static int yaffs_free_verification_failures; + +void yaffs_verify_free_chunks(struct yaffs_dev *dev) +{ + int counted; + int difference; + + if (yaffs_skip_verification(dev)) + return; + + counted = yaffs_count_free_chunks(dev); + + difference = dev->n_free_chunks - counted; + + if (difference) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Freechunks verification failure %d %d %d", + dev->n_free_chunks, counted, difference); + yaffs_free_verification_failures++; + } +} + +int yaffs_verify_file_sane(struct yaffs_obj *in) +{ + (void) in; + return YAFFS_OK; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h new file mode 100644 index 0000000..4f4af8d --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_verify.h @@ -0,0 +1,43 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_VERIFY_H__ +#define __YAFFS_VERIFY_H__ + +#include "yaffs_guts.h" + +void yaffs_verify_blk(struct yaffs_dev *dev, struct yaffs_block_info *bi, + int n); +void yaffs_verify_collected_blk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, int n); +void yaffs_verify_blocks(struct yaffs_dev *dev); + +void yaffs_verify_oh(struct yaffs_obj *obj, struct yaffs_obj_hdr *oh, + struct yaffs_ext_tags *tags, int parent_check); +void yaffs_verify_file(struct yaffs_obj *obj); +void yaffs_verify_link(struct yaffs_obj *obj); +void yaffs_verify_symlink(struct yaffs_obj *obj); +void yaffs_verify_special(struct yaffs_obj *obj); +void yaffs_verify_obj(struct yaffs_obj *obj); +void yaffs_verify_objects(struct yaffs_dev *dev); +void yaffs_verify_obj_in_dir(struct yaffs_obj *obj); +void yaffs_verify_dir(struct yaffs_obj *directory); +void yaffs_verify_free_chunks(struct yaffs_dev *dev); + +int yaffs_verify_file_sane(struct yaffs_obj *obj); + +int yaffs_skip_verification(struct yaffs_dev *dev); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c new file mode 100644 index 0000000..d277e20 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.c @@ -0,0 +1,422 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_yaffs1.h" +#include "yportenv.h" +#include "yaffs_trace.h" +#include "yaffs_bitmap.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_nand.h" +#include "yaffs_attribs.h" + +int yaffs1_scan(struct yaffs_dev *dev) +{ + struct yaffs_ext_tags tags; + int blk; + int result; + int chunk; + int c; + int deleted; + enum yaffs_block_state state; + LIST_HEAD(hard_list); + struct yaffs_block_info *bi; + u32 seq_number; + struct yaffs_obj_hdr *oh; + struct yaffs_obj *in; + struct yaffs_obj *parent; + int alloc_failed = 0; + struct yaffs_shadow_fixer *shadow_fixers = NULL; + u8 *chunk_data; + + yaffs_trace(YAFFS_TRACE_SCAN, + "yaffs1_scan starts intstartblk %d intendblk %d...", + dev->internal_start_block, dev->internal_end_block); + + chunk_data = yaffs_get_temp_buffer(dev); + + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; + + /* Scan all the blocks to determine their state */ + bi = dev->block_info; + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; + blk++) { + yaffs_clear_chunk_bits(dev, blk); + bi->pages_in_use = 0; + bi->soft_del_pages = 0; + + yaffs_query_init_block_state(dev, blk, &state, &seq_number); + + bi->block_state = state; + bi->seq_number = seq_number; + + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) + bi->block_state = state = YAFFS_BLOCK_STATE_DEAD; + + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, + "Block scanning block %d state %d seq %d", + blk, state, seq_number); + + if (state == YAFFS_BLOCK_STATE_DEAD) { + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, + "block %d is bad", blk); + } else if (state == YAFFS_BLOCK_STATE_EMPTY) { + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); + dev->n_erased_blocks++; + dev->n_free_chunks += dev->param.chunks_per_block; + } + bi++; + } + + /* For each block.... */ + for (blk = dev->internal_start_block; + !alloc_failed && blk <= dev->internal_end_block; blk++) { + + cond_resched(); + + bi = yaffs_get_block_info(dev, blk); + state = bi->block_state; + + deleted = 0; + + /* For each chunk in each block that needs scanning.... */ + for (c = 0; + !alloc_failed && c < dev->param.chunks_per_block && + state == YAFFS_BLOCK_STATE_NEEDS_SCAN; c++) { + /* Read the tags and decide what to do */ + chunk = blk * dev->param.chunks_per_block + c; + + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, + &tags); + + /* Let's have a good look at this chunk... */ + + if (tags.ecc_result == YAFFS_ECC_RESULT_UNFIXED || + tags.is_deleted) { + /* YAFFS1 only... + * A deleted chunk + */ + deleted++; + dev->n_free_chunks++; + } else if (!tags.chunk_used) { + /* An unassigned chunk in the block + * This means that either the block is empty or + * this is the one being allocated from + */ + + if (c == 0) { + /* We're looking at the first chunk in + *the block so the block is unused */ + state = YAFFS_BLOCK_STATE_EMPTY; + dev->n_erased_blocks++; + } else { + /* this is the block being allocated */ + yaffs_trace(YAFFS_TRACE_SCAN, + " Allocating from %d %d", + blk, c); + state = YAFFS_BLOCK_STATE_ALLOCATING; + dev->alloc_block = blk; + dev->alloc_page = c; + dev->alloc_block_finder = blk; + + } + + dev->n_free_chunks += + (dev->param.chunks_per_block - c); + } else if (tags.chunk_id > 0) { + /* chunk_id > 0 so it is a data chunk... */ + unsigned int endpos; + + yaffs_set_chunk_bit(dev, blk, c); + bi->pages_in_use++; + + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + YAFFS_OBJECT_TYPE_FILE); + /* PutChunkIntoFile checks for a clash + * (two data chunks with the same chunk_id). + */ + + if (!in) + alloc_failed = 1; + + if (in) { + if (!yaffs_put_chunk_in_file + (in, tags.chunk_id, chunk, 1)) + alloc_failed = 1; + } + + endpos = + (tags.chunk_id - 1) * + dev->data_bytes_per_chunk + + tags.n_bytes; + if (in && + in->variant_type == + YAFFS_OBJECT_TYPE_FILE && + in->variant.file_variant.scanned_size < + endpos) { + in->variant.file_variant.scanned_size = + endpos; + if (!dev->param.use_header_file_size) { + in->variant. + file_variant.file_size = + in->variant. + file_variant.scanned_size; + } + + } + } else { + /* chunk_id == 0, so it is an ObjectHeader. + * Make the object + */ + yaffs_set_chunk_bit(dev, blk, c); + bi->pages_in_use++; + + result = yaffs_rd_chunk_tags_nand(dev, chunk, + chunk_data, + NULL); + + oh = (struct yaffs_obj_hdr *)chunk_data; + + in = yaffs_find_by_number(dev, tags.obj_id); + if (in && in->variant_type != oh->type) { + /* This should not happen, but somehow + * Wev'e ended up with an obj_id that + * has been reused but not yet deleted, + * and worse still it has changed type. + * Delete the old object. + */ + + yaffs_del_obj(in); + in = NULL; + } + + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + oh->type); + + if (!in) + alloc_failed = 1; + + if (in && oh->shadows_obj > 0) { + + struct yaffs_shadow_fixer *fixer; + fixer = + kmalloc(sizeof + (struct yaffs_shadow_fixer), + GFP_NOFS); + if (fixer) { + fixer->next = shadow_fixers; + shadow_fixers = fixer; + fixer->obj_id = tags.obj_id; + fixer->shadowed_id = + oh->shadows_obj; + yaffs_trace(YAFFS_TRACE_SCAN, + " Shadow fixer: %d shadows %d", + fixer->obj_id, + fixer->shadowed_id); + + } + + } + + if (in && in->valid) { + /* We have already filled this one. + * We have a duplicate and need to + * resolve it. */ + + unsigned existing_serial = in->serial; + unsigned new_serial = + tags.serial_number; + + if (((existing_serial + 1) & 3) == + new_serial) { + /* Use new one - destroy the + * exisiting one */ + yaffs_chunk_del(dev, + in->hdr_chunk, + 1, __LINE__); + in->valid = 0; + } else { + /* Use existing - destroy + * this one. */ + yaffs_chunk_del(dev, chunk, 1, + __LINE__); + } + } + + if (in && !in->valid && + (tags.obj_id == YAFFS_OBJECTID_ROOT || + tags.obj_id == + YAFFS_OBJECTID_LOSTNFOUND)) { + /* We only load some info, don't fiddle + * with directory structure */ + in->valid = 1; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + + } else if (in && !in->valid) { + /* we need to load this info */ + + in->valid = 1; + in->variant_type = oh->type; + + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + in->hdr_chunk = chunk; + in->serial = tags.serial_number; + + yaffs_set_obj_name_from_oh(in, oh); + in->dirty = 0; + + /* directory stuff... + * hook up to parent + */ + + parent = + yaffs_find_or_create_by_number + (dev, oh->parent_obj_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + if (!parent) + alloc_failed = 1; + if (parent && parent->variant_type == + YAFFS_OBJECT_TYPE_UNKNOWN) { + /* Set up as a directory */ + parent->variant_type = + YAFFS_OBJECT_TYPE_DIRECTORY; + INIT_LIST_HEAD(&parent-> + variant.dir_variant. + children); + } else if (!parent || + parent->variant_type != + YAFFS_OBJECT_TYPE_DIRECTORY) { + /* Hoosterman, a problem.... + * We're trying to use a + * non-directory as a directory + */ + + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + ); + parent = dev->lost_n_found; + } + + yaffs_add_obj_to_dir(parent, in); + + switch (in->variant_type) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: + if (dev->param. + use_header_file_size) + in->variant. + file_variant.file_size + = yaffs_oh_to_size(oh); + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + in->variant. + hardlink_variant.equiv_id = + oh->equiv_id; + list_add(&in->hard_links, + &hard_list); + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + in->variant.symlink_variant. + alias = + yaffs_clone_str(oh->alias); + if (!in->variant. + symlink_variant.alias) + alloc_failed = 1; + break; + } + } + } + } + + if (state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { + /* If we got this far while scanning, + * then the block is fully allocated. */ + state = YAFFS_BLOCK_STATE_FULL; + } + + if (state == YAFFS_BLOCK_STATE_ALLOCATING) { + /* If the block was partially allocated then + * treat it as fully allocated. */ + state = YAFFS_BLOCK_STATE_FULL; + dev->alloc_block = -1; + } + + bi->block_state = state; + + /* Now let's see if it was dirty */ + if (bi->pages_in_use == 0 && + !bi->has_shrink_hdr && + bi->block_state == YAFFS_BLOCK_STATE_FULL) + yaffs_block_became_dirty(dev, blk); + } + + /* Ok, we've done all the scanning. + * Fix up the hard link chains. + * We should now have scanned all the objects, now it's time to add + * these hardlinks. + */ + + yaffs_link_fixup(dev, &hard_list); + + /* + * Fix up any shadowed objects. + * There should not be more than one of these. + */ + { + struct yaffs_shadow_fixer *fixer; + struct yaffs_obj *obj; + + while (shadow_fixers) { + fixer = shadow_fixers; + shadow_fixers = fixer->next; + /* Complete the rename transaction by deleting the + * shadowed object then setting the object header + to unshadowed. + */ + obj = yaffs_find_by_number(dev, fixer->shadowed_id); + if (obj) + yaffs_del_obj(obj); + + obj = yaffs_find_by_number(dev, fixer->obj_id); + + if (obj) + yaffs_update_oh(obj, NULL, 1, 0, 0, NULL); + + kfree(fixer); + } + } + + yaffs_release_temp_buffer(dev, chunk_data); + + if (alloc_failed) + return YAFFS_FAIL; + + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs1_scan ends"); + + return YAFFS_OK; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h new file mode 100644 index 0000000..97e2fdd --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs1.h @@ -0,0 +1,22 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_YAFFS1_H__ +#define __YAFFS_YAFFS1_H__ + +#include "yaffs_guts.h" +int yaffs1_scan(struct yaffs_dev *dev); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c new file mode 100644 index 0000000..f1dc972 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.c @@ -0,0 +1,1532 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffs_guts.h" +#include "yaffs_trace.h" +#include "yaffs_yaffs2.h" +#include "yaffs_checkptrw.h" +#include "yaffs_bitmap.h" +#include "yaffs_nand.h" +#include "yaffs_getblockinfo.h" +#include "yaffs_verify.h" +#include "yaffs_attribs.h" +#include "yaffs_summary.h" + +/* + * Checkpoints are really no benefit on very small partitions. + * + * To save space on small partitions don't bother with checkpoints unless + * the partition is at least this big. + */ +#define YAFFS_CHECKPOINT_MIN_BLOCKS 60 +#define YAFFS_SMALL_HOLE_THRESHOLD 4 + +/* + * Oldest Dirty Sequence Number handling. + */ + +/* yaffs_calc_oldest_dirty_seq() + * yaffs2_find_oldest_dirty_seq() + * Calculate the oldest dirty sequence number if we don't know it. + */ +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev) +{ + int i; + unsigned seq; + unsigned block_no = 0; + struct yaffs_block_info *b; + + if (!dev->param.is_yaffs2) + return; + + /* Find the oldest dirty sequence number. */ + seq = dev->seq_number + 1; + b = dev->block_info; + for (i = dev->internal_start_block; i <= dev->internal_end_block; i++) { + if (b->block_state == YAFFS_BLOCK_STATE_FULL && + (b->pages_in_use - b->soft_del_pages) < + dev->param.chunks_per_block && + b->seq_number < seq) { + seq = b->seq_number; + block_no = i; + } + b++; + } + + if (block_no) { + dev->oldest_dirty_seq = seq; + dev->oldest_dirty_block = block_no; + } +} + +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev) +{ + if (!dev->param.is_yaffs2) + return; + + if (!dev->oldest_dirty_seq) + yaffs_calc_oldest_dirty_seq(dev); +} + +/* + * yaffs_clear_oldest_dirty_seq() + * Called when a block is erased or marked bad. (ie. when its seq_number + * becomes invalid). If the value matches the oldest then we clear + * dev->oldest_dirty_seq to force its recomputation. + */ +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, + struct yaffs_block_info *bi) +{ + + if (!dev->param.is_yaffs2) + return; + + if (!bi || bi->seq_number == dev->oldest_dirty_seq) { + dev->oldest_dirty_seq = 0; + dev->oldest_dirty_block = 0; + } +} + +/* + * yaffs2_update_oldest_dirty_seq() + * Update the oldest dirty sequence number whenever we dirty a block. + * Only do this if the oldest_dirty_seq is actually being tracked. + */ +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, + struct yaffs_block_info *bi) +{ + if (!dev->param.is_yaffs2) + return; + + if (dev->oldest_dirty_seq) { + if (dev->oldest_dirty_seq > bi->seq_number) { + dev->oldest_dirty_seq = bi->seq_number; + dev->oldest_dirty_block = block_no; + } + } +} + +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi) +{ + + if (!dev->param.is_yaffs2) + return 1; /* disqualification only applies to yaffs2. */ + + if (!bi->has_shrink_hdr) + return 1; /* can gc */ + + yaffs2_find_oldest_dirty_seq(dev); + + /* Can't do gc of this block if there are any blocks older than this + * one that have discarded pages. + */ + return (bi->seq_number <= dev->oldest_dirty_seq); +} + +/* + * yaffs2_find_refresh_block() + * periodically finds the oldest full block by sequence number for refreshing. + * Only for yaffs2. + */ +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev) +{ + u32 b; + u32 oldest = 0; + u32 oldest_seq = 0; + struct yaffs_block_info *bi; + + if (!dev->param.is_yaffs2) + return oldest; + + /* + * If refresh period < 10 then refreshing is disabled. + */ + if (dev->param.refresh_period < 10) + return oldest; + + /* + * Fix broken values. + */ + if (dev->refresh_skip > dev->param.refresh_period) + dev->refresh_skip = dev->param.refresh_period; + + if (dev->refresh_skip > 0) + return oldest; + + /* + * Refresh skip is now zero. + * We'll do a refresh this time around.... + * Update the refresh skip and find the oldest block. + */ + dev->refresh_skip = dev->param.refresh_period; + dev->refresh_count++; + bi = dev->block_info; + for (b = dev->internal_start_block; b <= dev->internal_end_block; b++) { + + if (bi->block_state == YAFFS_BLOCK_STATE_FULL) { + + if (oldest < 1 || bi->seq_number < oldest_seq) { + oldest = b; + oldest_seq = bi->seq_number; + } + } + bi++; + } + + if (oldest > 0) { + yaffs_trace(YAFFS_TRACE_GC, + "GC refresh count %d selected block %d with seq_number %d", + dev->refresh_count, oldest, oldest_seq); + } + + return oldest; +} + +int yaffs2_checkpt_required(struct yaffs_dev *dev) +{ + int nblocks; + + if (!dev->param.is_yaffs2) + return 0; + + nblocks = dev->internal_end_block - dev->internal_start_block + 1; + + return !dev->param.skip_checkpt_wr && + !dev->read_only && (nblocks >= YAFFS_CHECKPOINT_MIN_BLOCKS); +} + +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev) +{ + int retval; + int n_bytes = 0; + int n_blocks; + int dev_blocks; + + if (!dev->param.is_yaffs2) + return 0; + + if (!dev->checkpoint_blocks_required && yaffs2_checkpt_required(dev)) { + /* Not a valid value so recalculate */ + dev_blocks = dev->param.end_block - dev->param.start_block + 1; + n_bytes += sizeof(struct yaffs_checkpt_validity); + n_bytes += sizeof(struct yaffs_checkpt_dev); + n_bytes += dev_blocks * sizeof(struct yaffs_block_info); + n_bytes += dev_blocks * dev->chunk_bit_stride; + n_bytes += + (sizeof(struct yaffs_checkpt_obj) + sizeof(u32)) * + dev->n_obj; + n_bytes += (dev->tnode_size + sizeof(u32)) * dev->n_tnodes; + n_bytes += sizeof(struct yaffs_checkpt_validity); + n_bytes += sizeof(u32); /* checksum */ + + /* Round up and add 2 blocks to allow for some bad blocks, + * so add 3 */ + + n_blocks = + (n_bytes / + (dev->data_bytes_per_chunk * + dev->param.chunks_per_block)) + 3; + + dev->checkpoint_blocks_required = n_blocks; + } + + retval = dev->checkpoint_blocks_required - dev->blocks_in_checkpt; + if (retval < 0) + retval = 0; + return retval; +} + +/*--------------------- Checkpointing --------------------*/ + +static int yaffs2_wr_checkpt_validity_marker(struct yaffs_dev *dev, int head) +{ + struct yaffs_checkpt_validity cp; + + memset(&cp, 0, sizeof(cp)); + + cp.struct_type = sizeof(cp); + cp.magic = YAFFS_MAGIC; + cp.version = YAFFS_CHECKPOINT_VERSION; + cp.head = (head) ? 1 : 0; + + return (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)) ? 1 : 0; +} + +static int yaffs2_rd_checkpt_validity_marker(struct yaffs_dev *dev, int head) +{ + struct yaffs_checkpt_validity cp; + int ok; + + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + + if (ok) + ok = (cp.struct_type == sizeof(cp)) && + (cp.magic == YAFFS_MAGIC) && + (cp.version == YAFFS_CHECKPOINT_VERSION) && + (cp.head == ((head) ? 1 : 0)); + return ok ? 1 : 0; +} + +static void yaffs2_dev_to_checkpt_dev(struct yaffs_checkpt_dev *cp, + struct yaffs_dev *dev) +{ + cp->n_erased_blocks = dev->n_erased_blocks; + cp->alloc_block = dev->alloc_block; + cp->alloc_page = dev->alloc_page; + cp->n_free_chunks = dev->n_free_chunks; + + cp->n_deleted_files = dev->n_deleted_files; + cp->n_unlinked_files = dev->n_unlinked_files; + cp->n_bg_deletions = dev->n_bg_deletions; + cp->seq_number = dev->seq_number; + +} + +static void yaffs_checkpt_dev_to_dev(struct yaffs_dev *dev, + struct yaffs_checkpt_dev *cp) +{ + dev->n_erased_blocks = cp->n_erased_blocks; + dev->alloc_block = cp->alloc_block; + dev->alloc_page = cp->alloc_page; + dev->n_free_chunks = cp->n_free_chunks; + + dev->n_deleted_files = cp->n_deleted_files; + dev->n_unlinked_files = cp->n_unlinked_files; + dev->n_bg_deletions = cp->n_bg_deletions; + dev->seq_number = cp->seq_number; +} + +static int yaffs2_wr_checkpt_dev(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_dev cp; + u32 n_bytes; + u32 n_blocks = dev->internal_end_block - dev->internal_start_block + 1; + int ok; + + /* Write device runtime values */ + yaffs2_dev_to_checkpt_dev(&cp, dev); + cp.struct_type = sizeof(cp); + + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); + if (!ok) + return 0; + + /* Write block info */ + n_bytes = n_blocks * sizeof(struct yaffs_block_info); + ok = (yaffs2_checkpt_wr(dev, dev->block_info, n_bytes) == n_bytes); + if (!ok) + return 0; + + /* Write chunk bits */ + n_bytes = n_blocks * dev->chunk_bit_stride; + ok = (yaffs2_checkpt_wr(dev, dev->chunk_bits, n_bytes) == n_bytes); + + return ok ? 1 : 0; +} + +static int yaffs2_rd_checkpt_dev(struct yaffs_dev *dev) +{ + struct yaffs_checkpt_dev cp; + u32 n_bytes; + u32 n_blocks = + (dev->internal_end_block - dev->internal_start_block + 1); + int ok; + + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + if (!ok) + return 0; + + if (cp.struct_type != sizeof(cp)) + return 0; + + yaffs_checkpt_dev_to_dev(dev, &cp); + + n_bytes = n_blocks * sizeof(struct yaffs_block_info); + + ok = (yaffs2_checkpt_rd(dev, dev->block_info, n_bytes) == n_bytes); + + if (!ok) + return 0; + + n_bytes = n_blocks * dev->chunk_bit_stride; + + ok = (yaffs2_checkpt_rd(dev, dev->chunk_bits, n_bytes) == n_bytes); + + return ok ? 1 : 0; +} + +static void yaffs2_obj_checkpt_obj(struct yaffs_checkpt_obj *cp, + struct yaffs_obj *obj) +{ + cp->obj_id = obj->obj_id; + cp->parent_id = (obj->parent) ? obj->parent->obj_id : 0; + cp->hdr_chunk = obj->hdr_chunk; + cp->variant_type = obj->variant_type; + cp->deleted = obj->deleted; + cp->soft_del = obj->soft_del; + cp->unlinked = obj->unlinked; + cp->fake = obj->fake; + cp->rename_allowed = obj->rename_allowed; + cp->unlink_allowed = obj->unlink_allowed; + cp->serial = obj->serial; + cp->n_data_chunks = obj->n_data_chunks; + + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + cp->size_or_equiv_obj = obj->variant.file_variant.file_size; + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) + cp->size_or_equiv_obj = obj->variant.hardlink_variant.equiv_id; +} + +static int yaffs2_checkpt_obj_to_obj(struct yaffs_obj *obj, + struct yaffs_checkpt_obj *cp) +{ + struct yaffs_obj *parent; + + if (obj->variant_type != cp->variant_type) { + yaffs_trace(YAFFS_TRACE_ERROR, + "Checkpoint read object %d type %d chunk %d does not match existing object type %d", + cp->obj_id, cp->variant_type, cp->hdr_chunk, + obj->variant_type); + return 0; + } + + obj->obj_id = cp->obj_id; + + if (cp->parent_id) + parent = yaffs_find_or_create_by_number(obj->my_dev, + cp->parent_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + else + parent = NULL; + + if (parent) { + if (parent->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Checkpoint read object %d parent %d type %d chunk %d Parent type, %d, not directory", + cp->obj_id, cp->parent_id, + cp->variant_type, cp->hdr_chunk, + parent->variant_type); + return 0; + } + yaffs_add_obj_to_dir(parent, obj); + } + + obj->hdr_chunk = cp->hdr_chunk; + obj->variant_type = cp->variant_type; + obj->deleted = cp->deleted; + obj->soft_del = cp->soft_del; + obj->unlinked = cp->unlinked; + obj->fake = cp->fake; + obj->rename_allowed = cp->rename_allowed; + obj->unlink_allowed = cp->unlink_allowed; + obj->serial = cp->serial; + obj->n_data_chunks = cp->n_data_chunks; + + if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + obj->variant.file_variant.file_size = cp->size_or_equiv_obj; + else if (obj->variant_type == YAFFS_OBJECT_TYPE_HARDLINK) + obj->variant.hardlink_variant.equiv_id = cp->size_or_equiv_obj; + + if (obj->hdr_chunk > 0) + obj->lazy_loaded = 1; + return 1; +} + +static int yaffs2_checkpt_tnode_worker(struct yaffs_obj *in, + struct yaffs_tnode *tn, u32 level, + int chunk_offset) +{ + int i; + struct yaffs_dev *dev = in->my_dev; + int ok = 1; + u32 base_offset; + + if (!tn) + return 1; + + if (level > 0) { + for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) { + if (!tn->internal[i]) + continue; + ok = yaffs2_checkpt_tnode_worker(in, + tn->internal[i], + level - 1, + (chunk_offset << + YAFFS_TNODES_INTERNAL_BITS) + i); + } + return ok; + } + + /* Level 0 tnode */ + base_offset = chunk_offset << YAFFS_TNODES_LEVEL0_BITS; + ok = (yaffs2_checkpt_wr(dev, &base_offset, sizeof(base_offset)) == + sizeof(base_offset)); + if (ok) + ok = (yaffs2_checkpt_wr(dev, tn, dev->tnode_size) == + dev->tnode_size); + + return ok; +} + +static int yaffs2_wr_checkpt_tnodes(struct yaffs_obj *obj) +{ + u32 end_marker = ~0; + int ok = 1; + + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) + return ok; + + ok = yaffs2_checkpt_tnode_worker(obj, + obj->variant.file_variant.top, + obj->variant.file_variant. + top_level, 0); + if (ok) + ok = (yaffs2_checkpt_wr(obj->my_dev, &end_marker, + sizeof(end_marker)) == sizeof(end_marker)); + + return ok ? 1 : 0; +} + +static int yaffs2_rd_checkpt_tnodes(struct yaffs_obj *obj) +{ + u32 base_chunk; + int ok = 1; + struct yaffs_dev *dev = obj->my_dev; + struct yaffs_file_var *file_stuct_ptr = &obj->variant.file_variant; + struct yaffs_tnode *tn; + int nread = 0; + + ok = (yaffs2_checkpt_rd(dev, &base_chunk, sizeof(base_chunk)) == + sizeof(base_chunk)); + + while (ok && (~base_chunk)) { + nread++; + /* Read level 0 tnode */ + + tn = yaffs_get_tnode(dev); + if (tn) + ok = (yaffs2_checkpt_rd(dev, tn, dev->tnode_size) == + dev->tnode_size); + else + ok = 0; + + if (tn && ok) + ok = yaffs_add_find_tnode_0(dev, + file_stuct_ptr, + base_chunk, tn) ? 1 : 0; + + if (ok) + ok = (yaffs2_checkpt_rd + (dev, &base_chunk, + sizeof(base_chunk)) == sizeof(base_chunk)); + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "Checkpoint read tnodes %d records, last %d. ok %d", + nread, base_chunk, ok); + + return ok ? 1 : 0; +} + +static int yaffs2_wr_checkpt_objs(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + struct yaffs_checkpt_obj cp; + int i; + int ok = 1; + struct list_head *lh; + + /* Iterate through the objects in each hash entry, + * dumping them to the checkpointing stream. + */ + + for (i = 0; ok && i < YAFFS_NOBJECT_BUCKETS; i++) { + list_for_each(lh, &dev->obj_bucket[i].list) { + obj = list_entry(lh, struct yaffs_obj, hash_link); + if (!obj->defered_free) { + yaffs2_obj_checkpt_obj(&cp, obj); + cp.struct_type = sizeof(cp); + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "Checkpoint write object %d parent %d type %d chunk %d obj addr %p", + cp.obj_id, cp.parent_id, + cp.variant_type, cp.hdr_chunk, obj); + + ok = (yaffs2_checkpt_wr(dev, &cp, + sizeof(cp)) == sizeof(cp)); + + if (ok && + obj->variant_type == + YAFFS_OBJECT_TYPE_FILE) + ok = yaffs2_wr_checkpt_tnodes(obj); + } + } + } + + /* Dump end of list */ + memset(&cp, 0xff, sizeof(struct yaffs_checkpt_obj)); + cp.struct_type = sizeof(cp); + + if (ok) + ok = (yaffs2_checkpt_wr(dev, &cp, sizeof(cp)) == sizeof(cp)); + + return ok ? 1 : 0; +} + +static int yaffs2_rd_checkpt_objs(struct yaffs_dev *dev) +{ + struct yaffs_obj *obj; + struct yaffs_checkpt_obj cp; + int ok = 1; + int done = 0; + LIST_HEAD(hard_list); + + + while (ok && !done) { + ok = (yaffs2_checkpt_rd(dev, &cp, sizeof(cp)) == sizeof(cp)); + if (cp.struct_type != sizeof(cp)) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "struct size %d instead of %d ok %d", + cp.struct_type, (int)sizeof(cp), ok); + ok = 0; + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "Checkpoint read object %d parent %d type %d chunk %d ", + cp.obj_id, cp.parent_id, cp.variant_type, + cp.hdr_chunk); + + if (ok && cp.obj_id == ~0) { + done = 1; + } else if (ok) { + obj = + yaffs_find_or_create_by_number(dev, cp.obj_id, + cp.variant_type); + if (obj) { + ok = yaffs2_checkpt_obj_to_obj(obj, &cp); + if (!ok) + break; + if (obj->variant_type == + YAFFS_OBJECT_TYPE_FILE) { + ok = yaffs2_rd_checkpt_tnodes(obj); + } else if (obj->variant_type == + YAFFS_OBJECT_TYPE_HARDLINK) { + list_add(&obj->hard_links, &hard_list); + } + } else { + ok = 0; + } + } + } + + if (ok) + yaffs_link_fixup(dev, &hard_list); + + return ok ? 1 : 0; +} + +static int yaffs2_wr_checkpt_sum(struct yaffs_dev *dev) +{ + u32 checkpt_sum; + int ok; + + yaffs2_get_checkpt_sum(dev, &checkpt_sum); + + ok = (yaffs2_checkpt_wr(dev, &checkpt_sum, sizeof(checkpt_sum)) == + sizeof(checkpt_sum)); + + if (!ok) + return 0; + + return 1; +} + +static int yaffs2_rd_checkpt_sum(struct yaffs_dev *dev) +{ + u32 checkpt_sum0; + u32 checkpt_sum1; + int ok; + + yaffs2_get_checkpt_sum(dev, &checkpt_sum0); + + ok = (yaffs2_checkpt_rd(dev, &checkpt_sum1, sizeof(checkpt_sum1)) == + sizeof(checkpt_sum1)); + + if (!ok) + return 0; + + if (checkpt_sum0 != checkpt_sum1) + return 0; + + return 1; +} + +static int yaffs2_wr_checkpt_data(struct yaffs_dev *dev) +{ + int ok = 1; + + if (!yaffs2_checkpt_required(dev)) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "skipping checkpoint write"); + ok = 0; + } + + if (ok) + ok = yaffs2_checkpt_open(dev, 1); + + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint validity"); + ok = yaffs2_wr_checkpt_validity_marker(dev, 1); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint device"); + ok = yaffs2_wr_checkpt_dev(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint objects"); + ok = yaffs2_wr_checkpt_objs(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "write checkpoint validity"); + ok = yaffs2_wr_checkpt_validity_marker(dev, 0); + } + + if (ok) + ok = yaffs2_wr_checkpt_sum(dev); + + if (!yaffs_checkpt_close(dev)) + ok = 0; + + if (ok) + dev->is_checkpointed = 1; + else + dev->is_checkpointed = 0; + + return dev->is_checkpointed; +} + +static int yaffs2_rd_checkpt_data(struct yaffs_dev *dev) +{ + int ok = 1; + + if (!dev->param.is_yaffs2) + ok = 0; + + if (ok && dev->param.skip_checkpt_rd) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "skipping checkpoint read"); + ok = 0; + } + + if (ok) + ok = yaffs2_checkpt_open(dev, 0); /* open for read */ + + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint validity"); + ok = yaffs2_rd_checkpt_validity_marker(dev, 1); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint device"); + ok = yaffs2_rd_checkpt_dev(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint objects"); + ok = yaffs2_rd_checkpt_objs(dev); + } + if (ok) { + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint validity"); + ok = yaffs2_rd_checkpt_validity_marker(dev, 0); + } + + if (ok) { + ok = yaffs2_rd_checkpt_sum(dev); + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "read checkpoint checksum %d", ok); + } + + if (!yaffs_checkpt_close(dev)) + ok = 0; + + if (ok) + dev->is_checkpointed = 1; + else + dev->is_checkpointed = 0; + + return ok ? 1 : 0; +} + +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev) +{ + if (dev->is_checkpointed || dev->blocks_in_checkpt > 0) { + dev->is_checkpointed = 0; + yaffs2_checkpt_invalidate_stream(dev); + } + if (dev->param.sb_dirty_fn) + dev->param.sb_dirty_fn(dev); +} + +int yaffs_checkpoint_save(struct yaffs_dev *dev) +{ + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "save entry: is_checkpointed %d", + dev->is_checkpointed); + + yaffs_verify_objects(dev); + yaffs_verify_blocks(dev); + yaffs_verify_free_chunks(dev); + + if (!dev->is_checkpointed) { + yaffs2_checkpt_invalidate(dev); + yaffs2_wr_checkpt_data(dev); + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT | YAFFS_TRACE_MOUNT, + "save exit: is_checkpointed %d", + dev->is_checkpointed); + + return dev->is_checkpointed; +} + +int yaffs2_checkpt_restore(struct yaffs_dev *dev) +{ + int retval; + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "restore entry: is_checkpointed %d", + dev->is_checkpointed); + + retval = yaffs2_rd_checkpt_data(dev); + + if (dev->is_checkpointed) { + yaffs_verify_objects(dev); + yaffs_verify_blocks(dev); + yaffs_verify_free_chunks(dev); + } + + yaffs_trace(YAFFS_TRACE_CHECKPOINT, + "restore exit: is_checkpointed %d", + dev->is_checkpointed); + + return retval; +} + +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size) +{ + /* if new_size > old_file_size. + * We're going to be writing a hole. + * If the hole is small then write zeros otherwise write a start + * of hole marker. + */ + loff_t old_file_size; + loff_t increase; + int small_hole; + int result = YAFFS_OK; + struct yaffs_dev *dev = NULL; + u8 *local_buffer = NULL; + int small_increase_ok = 0; + + if (!obj) + return YAFFS_FAIL; + + if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) + return YAFFS_FAIL; + + dev = obj->my_dev; + + /* Bail out if not yaffs2 mode */ + if (!dev->param.is_yaffs2) + return YAFFS_OK; + + old_file_size = obj->variant.file_variant.file_size; + + if (new_size <= old_file_size) + return YAFFS_OK; + + increase = new_size - old_file_size; + + if (increase < YAFFS_SMALL_HOLE_THRESHOLD * dev->data_bytes_per_chunk && + yaffs_check_alloc_available(dev, YAFFS_SMALL_HOLE_THRESHOLD + 1)) + small_hole = 1; + else + small_hole = 0; + + if (small_hole) + local_buffer = yaffs_get_temp_buffer(dev); + + if (local_buffer) { + /* fill hole with zero bytes */ + loff_t pos = old_file_size; + int this_write; + int written; + memset(local_buffer, 0, dev->data_bytes_per_chunk); + small_increase_ok = 1; + + while (increase > 0 && small_increase_ok) { + this_write = increase; + if (this_write > dev->data_bytes_per_chunk) + this_write = dev->data_bytes_per_chunk; + written = + yaffs_do_file_wr(obj, local_buffer, pos, this_write, + 0); + if (written == this_write) { + pos += this_write; + increase -= this_write; + } else { + small_increase_ok = 0; + } + } + + yaffs_release_temp_buffer(dev, local_buffer); + + /* If out of space then reverse any chunks we've added */ + if (!small_increase_ok) + yaffs_resize_file_down(obj, old_file_size); + } + + if (!small_increase_ok && + obj->parent && + obj->parent->obj_id != YAFFS_OBJECTID_UNLINKED && + obj->parent->obj_id != YAFFS_OBJECTID_DELETED) { + /* Write a hole start header with the old file size */ + yaffs_update_oh(obj, NULL, 0, 1, 0, NULL); + } + + return result; +} + +struct yaffs_block_index { + int seq; + int block; +}; + +static int yaffs2_ybicmp(const void *a, const void *b) +{ + int aseq = ((struct yaffs_block_index *)a)->seq; + int bseq = ((struct yaffs_block_index *)b)->seq; + int ablock = ((struct yaffs_block_index *)a)->block; + int bblock = ((struct yaffs_block_index *)b)->block; + + if (aseq == bseq) + return ablock - bblock; + + return aseq - bseq; +} + +static inline int yaffs2_scan_chunk(struct yaffs_dev *dev, + struct yaffs_block_info *bi, + int blk, int chunk_in_block, + int *found_chunks, + u8 *chunk_data, + struct list_head *hard_list, + int summary_available) +{ + struct yaffs_obj_hdr *oh; + struct yaffs_obj *in; + struct yaffs_obj *parent; + int equiv_id; + loff_t file_size; + int is_shrink; + int is_unlinked; + struct yaffs_ext_tags tags; + int result; + int alloc_failed = 0; + int chunk = blk * dev->param.chunks_per_block + chunk_in_block; + struct yaffs_file_var *file_var; + struct yaffs_hardlink_var *hl_var; + struct yaffs_symlink_var *sl_var; + + if (summary_available) { + result = yaffs_summary_fetch(dev, &tags, chunk_in_block); + tags.seq_number = bi->seq_number; + } + + if (!summary_available || tags.obj_id == 0) { + result = yaffs_rd_chunk_tags_nand(dev, chunk, NULL, &tags); + dev->tags_used++; + } else { + dev->summary_used++; + } + + /* Let's have a good look at this chunk... */ + + if (!tags.chunk_used) { + /* An unassigned chunk in the block. + * If there are used chunks after this one, then + * it is a chunk that was skipped due to failing + * the erased check. Just skip it so that it can + * be deleted. + * But, more typically, We get here when this is + * an unallocated chunk and his means that + * either the block is empty or this is the one + * being allocated from + */ + + if (*found_chunks) { + /* This is a chunk that was skipped due + * to failing the erased check */ + } else if (chunk_in_block == 0) { + /* We're looking at the first chunk in + * the block so the block is unused */ + bi->block_state = YAFFS_BLOCK_STATE_EMPTY; + dev->n_erased_blocks++; + } else { + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING) { + if (dev->seq_number == bi->seq_number) { + /* Allocating from this block*/ + yaffs_trace(YAFFS_TRACE_SCAN, + " Allocating from %d %d", + blk, chunk_in_block); + + bi->block_state = + YAFFS_BLOCK_STATE_ALLOCATING; + dev->alloc_block = blk; + dev->alloc_page = chunk_in_block; + dev->alloc_block_finder = blk; + } else { + /* This is a partially written block + * that is not the current + * allocation block. + */ + yaffs_trace(YAFFS_TRACE_SCAN, + "Partially written block %d detected. gc will fix this.", + blk); + } + } + } + + dev->n_free_chunks++; + + } else if (tags.ecc_result == + YAFFS_ECC_RESULT_UNFIXED) { + yaffs_trace(YAFFS_TRACE_SCAN, + " Unfixed ECC in chunk(%d:%d), chunk ignored", + blk, chunk_in_block); + dev->n_free_chunks++; + } else if (tags.obj_id > YAFFS_MAX_OBJECT_ID || + tags.chunk_id > YAFFS_MAX_CHUNK_ID || + tags.obj_id == YAFFS_OBJECTID_SUMMARY || + (tags.chunk_id > 0 && + tags.n_bytes > dev->data_bytes_per_chunk) || + tags.seq_number != bi->seq_number) { + yaffs_trace(YAFFS_TRACE_SCAN, + "Chunk (%d:%d) with bad tags:obj = %d, chunk_id = %d, n_bytes = %d, ignored", + blk, chunk_in_block, tags.obj_id, + tags.chunk_id, tags.n_bytes); + dev->n_free_chunks++; + } else if (tags.chunk_id > 0) { + /* chunk_id > 0 so it is a data chunk... */ + loff_t endpos; + loff_t chunk_base = (tags.chunk_id - 1) * + dev->data_bytes_per_chunk; + + *found_chunks = 1; + + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + YAFFS_OBJECT_TYPE_FILE); + if (!in) + /* Out of memory */ + alloc_failed = 1; + + if (in && + in->variant_type == YAFFS_OBJECT_TYPE_FILE && + chunk_base < in->variant.file_variant.shrink_size) { + /* This has not been invalidated by + * a resize */ + if (!yaffs_put_chunk_in_file(in, tags.chunk_id, + chunk, -1)) + alloc_failed = 1; + + /* File size is calculated by looking at + * the data chunks if we have not + * seen an object header yet. + * Stop this practice once we find an + * object header. + */ + endpos = chunk_base + tags.n_bytes; + + if (!in->valid && + in->variant.file_variant.scanned_size < endpos) { + in->variant.file_variant. + scanned_size = endpos; + in->variant.file_variant. + file_size = endpos; + } + } else if (in) { + /* This chunk has been invalidated by a + * resize, or a past file deletion + * so delete the chunk*/ + yaffs_chunk_del(dev, chunk, 1, __LINE__); + } + } else { + /* chunk_id == 0, so it is an ObjectHeader. + * Thus, we read in the object header and make + * the object + */ + *found_chunks = 1; + + yaffs_set_chunk_bit(dev, blk, chunk_in_block); + bi->pages_in_use++; + + oh = NULL; + in = NULL; + + if (tags.extra_available) { + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, + tags.extra_obj_type); + if (!in) + alloc_failed = 1; + } + + if (!in || + (!in->valid && dev->param.disable_lazy_load) || + tags.extra_shadows || + (!in->valid && (tags.obj_id == YAFFS_OBJECTID_ROOT || + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND))) { + + /* If we don't have valid info then we + * need to read the chunk + * TODO In future we can probably defer + * reading the chunk and living with + * invalid data until needed. + */ + + result = yaffs_rd_chunk_tags_nand(dev, + chunk, + chunk_data, + NULL); + + oh = (struct yaffs_obj_hdr *)chunk_data; + + if (dev->param.inband_tags) { + /* Fix up the header if they got + * corrupted by inband tags */ + oh->shadows_obj = + oh->inband_shadowed_obj_id; + oh->is_shrink = + oh->inband_is_shrink; + } + + if (!in) { + in = yaffs_find_or_create_by_number(dev, + tags.obj_id, oh->type); + if (!in) + alloc_failed = 1; + } + } + + if (!in) { + /* TODO Hoosterman we have a problem! */ + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: Could not make object for object %d at chunk %d during scan", + tags.obj_id, chunk); + return YAFFS_FAIL; + } + + if (in->valid) { + /* We have already filled this one. + * We have a duplicate that will be + * discarded, but we first have to suck + * out resize info if it is a file. + */ + if ((in->variant_type == YAFFS_OBJECT_TYPE_FILE) && + ((oh && oh->type == YAFFS_OBJECT_TYPE_FILE) || + (tags.extra_available && + tags.extra_obj_type == YAFFS_OBJECT_TYPE_FILE) + )) { + loff_t this_size = (oh) ? + yaffs_oh_to_size(oh) : + tags.extra_file_size; + u32 parent_obj_id = (oh) ? + oh->parent_obj_id : + tags.extra_parent_id; + + is_shrink = (oh) ? + oh->is_shrink : + tags.extra_is_shrink; + + /* If it is deleted (unlinked + * at start also means deleted) + * we treat the file size as + * being zeroed at this point. + */ + if (parent_obj_id == YAFFS_OBJECTID_DELETED || + parent_obj_id == YAFFS_OBJECTID_UNLINKED) { + this_size = 0; + is_shrink = 1; + } + + if (is_shrink && + in->variant.file_variant.shrink_size > + this_size) + in->variant.file_variant.shrink_size = + this_size; + + if (is_shrink) + bi->has_shrink_hdr = 1; + } + /* Use existing - destroy this one. */ + yaffs_chunk_del(dev, chunk, 1, __LINE__); + } + + if (!in->valid && in->variant_type != + (oh ? oh->type : tags.extra_obj_type)) + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: Bad object type, %d != %d, for object %d at chunk %d during scan", + oh ? oh->type : tags.extra_obj_type, + in->variant_type, tags.obj_id, + chunk); + + if (!in->valid && + (tags.obj_id == YAFFS_OBJECTID_ROOT || + tags.obj_id == YAFFS_OBJECTID_LOSTNFOUND)) { + /* We only load some info, don't fiddle + * with directory structure */ + in->valid = 1; + + if (oh) { + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + in->lazy_loaded = 0; + } else { + in->lazy_loaded = 1; + } + in->hdr_chunk = chunk; + + } else if (!in->valid) { + /* we need to load this info */ + in->valid = 1; + in->hdr_chunk = chunk; + if (oh) { + in->variant_type = oh->type; + in->yst_mode = oh->yst_mode; + yaffs_load_attribs(in, oh); + + if (oh->shadows_obj > 0) + yaffs_handle_shadowed_obj(dev, + oh->shadows_obj, 1); + + yaffs_set_obj_name_from_oh(in, oh); + parent = yaffs_find_or_create_by_number(dev, + oh->parent_obj_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + file_size = yaffs_oh_to_size(oh); + is_shrink = oh->is_shrink; + equiv_id = oh->equiv_id; + } else { + in->variant_type = tags.extra_obj_type; + parent = yaffs_find_or_create_by_number(dev, + tags.extra_parent_id, + YAFFS_OBJECT_TYPE_DIRECTORY); + file_size = tags.extra_file_size; + is_shrink = tags.extra_is_shrink; + equiv_id = tags.extra_equiv_id; + in->lazy_loaded = 1; + } + in->dirty = 0; + + if (!parent) + alloc_failed = 1; + + /* directory stuff... + * hook up to parent + */ + + if (parent && + parent->variant_type == YAFFS_OBJECT_TYPE_UNKNOWN) { + /* Set up as a directory */ + parent->variant_type = + YAFFS_OBJECT_TYPE_DIRECTORY; + INIT_LIST_HEAD(&parent-> + variant.dir_variant.children); + } else if (!parent || + parent->variant_type != + YAFFS_OBJECT_TYPE_DIRECTORY) { + /* Hoosterman, another problem.... + * Trying to use a non-directory as a directory + */ + + yaffs_trace(YAFFS_TRACE_ERROR, + "yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found." + ); + parent = dev->lost_n_found; + } + yaffs_add_obj_to_dir(parent, in); + + is_unlinked = (parent == dev->del_dir) || + (parent == dev->unlinked_dir); + + if (is_shrink) + /* Mark the block */ + bi->has_shrink_hdr = 1; + + /* Note re hardlinks. + * Since we might scan a hardlink before its equivalent + * object is scanned we put them all in a list. + * After scanning is complete, we should have all the + * objects, so we run through this list and fix up all + * the chains. + */ + + switch (in->variant_type) { + case YAFFS_OBJECT_TYPE_UNKNOWN: + /* Todo got a problem */ + break; + case YAFFS_OBJECT_TYPE_FILE: + file_var = &in->variant.file_variant; + if (file_var->scanned_size < file_size) { + /* This covers the case where the file + * size is greater than the data held. + * This will happen if the file is + * resized to be larger than its + * current data extents. + */ + file_var->file_size = file_size; + file_var->scanned_size = file_size; + } + + if (file_var->shrink_size > file_size) + file_var->shrink_size = file_size; + + break; + case YAFFS_OBJECT_TYPE_HARDLINK: + hl_var = &in->variant.hardlink_variant; + if (!is_unlinked) { + hl_var->equiv_id = equiv_id; + list_add(&in->hard_links, hard_list); + } + break; + case YAFFS_OBJECT_TYPE_DIRECTORY: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SPECIAL: + /* Do nothing */ + break; + case YAFFS_OBJECT_TYPE_SYMLINK: + sl_var = &in->variant.symlink_variant; + if (oh) { + sl_var->alias = + yaffs_clone_str(oh->alias); + if (!sl_var->alias) + alloc_failed = 1; + } + break; + } + } + } + return alloc_failed ? YAFFS_FAIL : YAFFS_OK; +} + +int yaffs2_scan_backwards(struct yaffs_dev *dev) +{ + int blk; + int block_iter; + int start_iter; + int end_iter; + int n_to_scan = 0; + enum yaffs_block_state state; + int c; + int deleted; + LIST_HEAD(hard_list); + struct yaffs_block_info *bi; + u32 seq_number; + int n_blocks = dev->internal_end_block - dev->internal_start_block + 1; + u8 *chunk_data; + int found_chunks; + int alloc_failed = 0; + struct yaffs_block_index *block_index = NULL; + int alt_block_index = 0; + int summary_available; + + yaffs_trace(YAFFS_TRACE_SCAN, + "yaffs2_scan_backwards starts intstartblk %d intendblk %d...", + dev->internal_start_block, dev->internal_end_block); + + dev->seq_number = YAFFS_LOWEST_SEQUENCE_NUMBER; + + block_index = + kmalloc(n_blocks * sizeof(struct yaffs_block_index), GFP_NOFS); + + if (!block_index) { + block_index = + vmalloc(n_blocks * sizeof(struct yaffs_block_index)); + alt_block_index = 1; + } + + if (!block_index) { + yaffs_trace(YAFFS_TRACE_SCAN, + "yaffs2_scan_backwards() could not allocate block index!" + ); + return YAFFS_FAIL; + } + + dev->blocks_in_checkpt = 0; + + chunk_data = yaffs_get_temp_buffer(dev); + + /* Scan all the blocks to determine their state */ + bi = dev->block_info; + for (blk = dev->internal_start_block; blk <= dev->internal_end_block; + blk++) { + yaffs_clear_chunk_bits(dev, blk); + bi->pages_in_use = 0; + bi->soft_del_pages = 0; + + yaffs_query_init_block_state(dev, blk, &state, &seq_number); + + bi->block_state = state; + bi->seq_number = seq_number; + + if (bi->seq_number == YAFFS_SEQUENCE_CHECKPOINT_DATA) + bi->block_state = YAFFS_BLOCK_STATE_CHECKPOINT; + if (bi->seq_number == YAFFS_SEQUENCE_BAD_BLOCK) + bi->block_state = YAFFS_BLOCK_STATE_DEAD; + + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, + "Block scanning block %d state %d seq %d", + blk, bi->block_state, seq_number); + + if (bi->block_state == YAFFS_BLOCK_STATE_CHECKPOINT) { + dev->blocks_in_checkpt++; + + } else if (bi->block_state == YAFFS_BLOCK_STATE_DEAD) { + yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, + "block %d is bad", blk); + } else if (bi->block_state == YAFFS_BLOCK_STATE_EMPTY) { + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "Block empty "); + dev->n_erased_blocks++; + dev->n_free_chunks += dev->param.chunks_per_block; + } else if (bi->block_state == + YAFFS_BLOCK_STATE_NEEDS_SCAN) { + /* Determine the highest sequence number */ + if (seq_number >= YAFFS_LOWEST_SEQUENCE_NUMBER && + seq_number < YAFFS_HIGHEST_SEQUENCE_NUMBER) { + block_index[n_to_scan].seq = seq_number; + block_index[n_to_scan].block = blk; + n_to_scan++; + if (seq_number >= dev->seq_number) + dev->seq_number = seq_number; + } else { + /* TODO: Nasty sequence number! */ + yaffs_trace(YAFFS_TRACE_SCAN, + "Block scanning block %d has bad sequence number %d", + blk, seq_number); + } + } + bi++; + } + + yaffs_trace(YAFFS_TRACE_SCAN, "%d blocks to be sorted...", n_to_scan); + + cond_resched(); + + /* Sort the blocks by sequence number */ + sort(block_index, n_to_scan, sizeof(struct yaffs_block_index), + yaffs2_ybicmp, NULL); + + cond_resched(); + + yaffs_trace(YAFFS_TRACE_SCAN, "...done"); + + /* Now scan the blocks looking at the data. */ + start_iter = 0; + end_iter = n_to_scan - 1; + yaffs_trace(YAFFS_TRACE_SCAN_DEBUG, "%d blocks to scan", n_to_scan); + + /* For each block.... backwards */ + for (block_iter = end_iter; + !alloc_failed && block_iter >= start_iter; + block_iter--) { + /* Cooperative multitasking! This loop can run for so + long that watchdog timers expire. */ + cond_resched(); + + /* get the block to scan in the correct order */ + blk = block_index[block_iter].block; + bi = yaffs_get_block_info(dev, blk); + deleted = 0; + + summary_available = yaffs_summary_read(dev, dev->sum_tags, blk); + + /* For each chunk in each block that needs scanning.... */ + found_chunks = 0; + if (summary_available) + c = dev->chunks_per_summary - 1; + else + c = dev->param.chunks_per_block - 1; + + for (/* c is already initialised */; + !alloc_failed && c >= 0 && + (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN || + bi->block_state == YAFFS_BLOCK_STATE_ALLOCATING); + c--) { + /* Scan backwards... + * Read the tags and decide what to do + */ + if (yaffs2_scan_chunk(dev, bi, blk, c, + &found_chunks, chunk_data, + &hard_list, summary_available) == + YAFFS_FAIL) + alloc_failed = 1; + } + + if (bi->block_state == YAFFS_BLOCK_STATE_NEEDS_SCAN) { + /* If we got this far while scanning, then the block + * is fully allocated. */ + bi->block_state = YAFFS_BLOCK_STATE_FULL; + } + + /* Now let's see if it was dirty */ + if (bi->pages_in_use == 0 && + !bi->has_shrink_hdr && + bi->block_state == YAFFS_BLOCK_STATE_FULL) { + yaffs_block_became_dirty(dev, blk); + } + } + + yaffs_skip_rest_of_block(dev); + + if (alt_block_index) + vfree(block_index); + else + kfree(block_index); + + /* Ok, we've done all the scanning. + * Fix up the hard link chains. + * We have scanned all the objects, now it's time to add these + * hardlinks. + */ + yaffs_link_fixup(dev, &hard_list); + + yaffs_release_temp_buffer(dev, chunk_data); + + if (alloc_failed) + return YAFFS_FAIL; + + yaffs_trace(YAFFS_TRACE_SCAN, "yaffs2_scan_backwards ends"); + + return YAFFS_OK; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h new file mode 100644 index 0000000..2363bfd --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffs_yaffs2.h @@ -0,0 +1,39 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_YAFFS2_H__ +#define __YAFFS_YAFFS2_H__ + +#include "yaffs_guts.h" + +void yaffs_calc_oldest_dirty_seq(struct yaffs_dev *dev); +void yaffs2_find_oldest_dirty_seq(struct yaffs_dev *dev); +void yaffs2_clear_oldest_dirty_seq(struct yaffs_dev *dev, + struct yaffs_block_info *bi); +void yaffs2_update_oldest_dirty_seq(struct yaffs_dev *dev, unsigned block_no, + struct yaffs_block_info *bi); +int yaffs_block_ok_for_gc(struct yaffs_dev *dev, struct yaffs_block_info *bi); +u32 yaffs2_find_refresh_block(struct yaffs_dev *dev); +int yaffs2_checkpt_required(struct yaffs_dev *dev); +int yaffs_calc_checkpt_blocks_required(struct yaffs_dev *dev); + +void yaffs2_checkpt_invalidate(struct yaffs_dev *dev); +int yaffs2_checkpt_save(struct yaffs_dev *dev); +int yaffs2_checkpt_restore(struct yaffs_dev *dev); + +int yaffs2_handle_hole(struct yaffs_obj *obj, loff_t new_size); +int yaffs2_scan_backwards(struct yaffs_dev *dev); + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h new file mode 100644 index 0000000..34235e9 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg.h @@ -0,0 +1,55 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * Header file for using yaffs in an application via + * a direct interface. + */ + + +#ifndef __YAFFSCFG_H__ +#define __YAFFSCFG_H__ + + +#include "yportenv.h" + +#define YAFFSFS_N_HANDLES 100 +#define YAFFSFS_N_DSC 20 +#define YAFFSFS_MNT_POINT "/nand" + +#define SIZE_1M 0x100000 +#define YAFFSFS_OFFSET (2*SIZE_1M) /* YAFFS2 file system start offset address */ +#define YAFFSFS_SIZE (10*SIZE_1M) /* YAFFS2 file system start offset address */ + +#define K9F2G08_PAGE_SIZE 2048 /* Nandflash pagesize: 2K */ +#define K9F2G08_BLOCK_SIZE 0x20000 /* Nandflash block size: 128K */ +#define K9F2G08_SPARE_SIZE 64 /* Nandflash spare area size: 64 */ + +#define NF_PAGE_SIZE K9F2G08_PAGE_SIZE +#define NF_BLOCK_SIZE K9F2G08_BLOCK_SIZE +#define NF_SPARE_SIZE K9F2G08_SPARE_SIZE + +#define YAFFSFS_START_BLOCK ( YAFFSFS_OFFSET/NF_BLOCK_SIZE ) +#define YAFFSFS_END_BLOCK ( YAFFSFS_START_BLOCK+(YAFFSFS_SIZE/NF_BLOCK_SIZE) ) + + +struct yaffsfs_DeviceConfiguration { + const YCHAR *prefix; + struct yaffs_dev *dev; +}; + + +#endif + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c new file mode 100644 index 0000000..5e4ed9d --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffscfg2k.c @@ -0,0 +1,121 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +/* + * yaffscfg2k.c The configuration for the "direct" use of yaffs. + * + * This file is intended to be modified to your requirements. + * There is no need to redistribute this file. + */ + +#include "yaffscfg.h" +#include "yaffs_guts.h" +#include "yaffsfs.h" +#include "yaffs_trace.h" +#include "yaffs_osglue.h" +#include "yaffs_k9f2g08.h" + +//#include <asm/errno.h> +//#include <errno.h> + +#if 1 +unsigned yaffs_trace_mask = + +// YAFFS_TRACE_SCAN | + YAFFS_TRACE_GC | +// YAFFS_TRACE_MTD | + YAFFS_TRACE_ERASE | + YAFFS_TRACE_ERROR | +// YAFFS_TRACE_TRACING | +// YAFFS_TRACE_ALLOCATE | + YAFFS_TRACE_BAD_BLOCKS | +// YAFFS_TRACE_VERIFY | +// YAFFS_TRACE_ALWAYS | + 0; +#else +unsigned yaffs_trace_mask = 0xFFFFFFFF; +#endif + + +int yaffs_devconfig(char *_mp, int start_block, int end_block) +{ + struct yaffs_dev *dev = NULL; + char *mp = NULL; + + dev = malloc(sizeof(*dev)); + mp = strdup(_mp); + + if (!dev || !mp) + { + /* Alloc error */ + printf("Failed to allocate memory\n"); + return -1; + } + + /* Seems sane, so configure */ + memset(dev, 0, sizeof(*dev)); + dev->param.name = mp; + dev->param.is_yaffs2 = 1; + + dev->param.total_bytes_per_chunk = NF_PAGE_SIZE; + dev->param.spare_bytes_per_chunk = NF_SPARE_SIZE; + dev->param.chunks_per_block = NF_BLOCK_SIZE / NF_PAGE_SIZE; + dev->param.start_block = start_block; + dev->param.end_block = end_block; + dev->param.n_reserved_blocks = 8; + + dev->param.inband_tags = 0; + dev->param.use_nand_ecc = 0; + dev->param.no_tags_ecc = 0; + dev->param.n_caches=0; + dev->param.empty_lost_n_found = 1; + dev->param.skip_checkpt_rd = 0; + dev->param.skip_checkpt_wr = 0; + dev->param.refresh_period = 1000; + + dev->param.initialise_flash_fn = ynf_init; + dev->param.erase_fn = ynf_erase_block; + dev->param.write_chunk_tags_fn = ynf_write_chunk_tags; + dev->param.read_chunk_tags_fn = ynf_read_chunk_tags; + dev->param.bad_block_fn = ynf_mark_block_bad; + dev->param.query_block_fn = ynf_query_block; + dev->driver_context = NULL; + + yaffs_add_device(dev); + + printf("Configures yaffs mount %s: start block %d, end block %d %s\n", + mp, start_block, end_block, dev->param.inband_tags ? "using inband tags" : ""); + return 0; +} + + +/* Configure the devices that will be used */ + +int yaffs_start_up(void) +{ + static int start_up_called = 0; + + if(start_up_called) + return 0; + start_up_called = 1; + + yaffs_devconfig(YAFFSFS_MNT_POINT, YAFFSFS_START_BLOCK, YAFFSFS_END_BLOCK); + + /* Call the OS initialisation (eg. set up lock semaphore */ + yaffsfs_OSInitialisation(); + + return 0; +} + + + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c new file mode 100644 index 0000000..dbf0557 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.c @@ -0,0 +1,3461 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * 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. + */ + +#include "yaffsfs.h" +#include "yaffs_guts.h" +#include "yaffscfg.h" +#include "yportenv.h" +#include "yaffs_trace.h" + +#include "string.h" + +#define YAFFSFS_MAX_SYMLINK_DEREFERENCES 5 + +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* YAFFSFS_RW_SIZE must be a power of 2 */ +#define YAFFSFS_RW_SHIFT (13) +#define YAFFSFS_RW_SIZE (1<<YAFFSFS_RW_SHIFT) + +/* Some forward references */ +static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relativeDirectory, + const YCHAR *path, + int symDepth, int getEquiv, + struct yaffs_obj **dirOut, + int *notDir, int *loop); + +static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj); + +unsigned int yaffs_wr_attempts; + +/* + * Handle management. + * There are open inodes in struct yaffsfs_Inode. + * There are open file descriptors in yaffsfs_FileDes. + * There are open handles in yaffsfs_FileDes. + * + * Things are structured this way to be like the Linux VFS model + * so that interactions with the yaffs guts calls are similar. + * That means more common code paths and less special code. + * That means better testing etc. + * + * We have 3 layers because: + * A handle is different than an fd because you can use dup() + * to create a new handle that accesses the *same* fd. The two + * handles will use the same offset (part of the fd). We only close + * down the fd when there are no more handles accessing it. + * + * More than one fd can currently access one file, but each fd + * has its own permsiions and offset. + */ + +struct yaffsfs_Inode { + int count; /* Number of handles accessing this inode */ + struct yaffs_obj *iObj; +}; + +struct yaffsfs_FileDes { + u8 reading:1; + u8 writing:1; + u8 append:1; + u8 shareRead:1; + u8 shareWrite:1; + int inodeId:12; /* Index to corresponding yaffsfs_Inode */ + int handleCount:10; /* Number of handles for this fd */ + Y_LOFF_T position; /* current position in file */ +}; + +struct yaffsfs_Handle { + short int fdId; + short int useCount; +}; + + +struct yaffsfs_DirSearchContxt { + struct yaffs_dirent de; /* directory entry */ + YCHAR name[NAME_MAX + 1]; /* name of directory being searched */ + struct yaffs_obj *dirObj; /* ptr to directory being searched */ + struct yaffs_obj *nextReturn; /* obj returned by next readddir */ + struct list_head others; + int offset:20; + unsigned inUse:1; +}; + +static struct yaffsfs_DirSearchContxt yaffsfs_dsc[YAFFSFS_N_DSC]; +static struct yaffsfs_Inode yaffsfs_inode[YAFFSFS_N_HANDLES]; +static struct yaffsfs_FileDes yaffsfs_fd[YAFFSFS_N_HANDLES]; +static struct yaffsfs_Handle yaffsfs_handle[YAFFSFS_N_HANDLES]; + +static int yaffsfs_handlesInitialised; + +unsigned yaffs_set_trace(unsigned tm) +{ + yaffs_trace_mask = tm; + return yaffs_trace_mask; +} + +unsigned yaffs_get_trace(void) +{ + return yaffs_trace_mask; +} + +/* + * yaffsfs_InitHandle + * Inilitalise handle management on start-up. + */ + +static void yaffsfs_InitHandles(void) +{ + int i; + if (yaffsfs_handlesInitialised) + return; + + memset(yaffsfs_inode, 0, sizeof(yaffsfs_inode)); + memset(yaffsfs_fd, 0, sizeof(yaffsfs_fd)); + memset(yaffsfs_handle, 0, sizeof(yaffsfs_handle)); + memset(yaffsfs_dsc, 0, sizeof(yaffsfs_dsc)); + + for (i = 0; i < YAFFSFS_N_HANDLES; i++) + yaffsfs_fd[i].inodeId = -1; + for (i = 0; i < YAFFSFS_N_HANDLES; i++) + yaffsfs_handle[i].fdId = -1; +} + +static struct yaffsfs_Handle *yaffsfs_HandleToPointer(int h) +{ + if (h >= 0 && h < YAFFSFS_N_HANDLES) + return &yaffsfs_handle[h]; + return NULL; +} + +static struct yaffsfs_FileDes *yaffsfs_HandleToFileDes(int handle) +{ + struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); + + if (h && h->useCount > 0 && h->fdId >= 0 && h->fdId < YAFFSFS_N_HANDLES) + return &yaffsfs_fd[h->fdId]; + + return NULL; +} + +static struct yaffsfs_Inode *yaffsfs_HandleToInode(int handle) +{ + struct yaffsfs_FileDes *fd = yaffsfs_HandleToFileDes(handle); + + if (fd && fd->handleCount > 0 && + fd->inodeId >= 0 && fd->inodeId < YAFFSFS_N_HANDLES) + return &yaffsfs_inode[fd->inodeId]; + + return NULL; +} + +static struct yaffs_obj *yaffsfs_HandleToObject(int handle) +{ + struct yaffsfs_Inode *in = yaffsfs_HandleToInode(handle); + + if (in) + return in->iObj; + + return NULL; +} + +/* + * yaffsfs_FindInodeIdForObject + * Find the inode entry for an object, if it exists. + */ + +static int yaffsfs_FindInodeIdForObject(struct yaffs_obj *obj) +{ + int i; + int ret = -1; + + if (obj) + obj = yaffs_get_equivalent_obj(obj); + + /* Look for it in open inode table */ + for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) { + if (yaffsfs_inode[i].iObj == obj) + ret = i; + } + return ret; +} + +/* + * yaffsfs_GetInodeIdForObject + * Grab an inode entry when opening a new inode. + */ +static int yaffsfs_GetInodeIdForObject(struct yaffs_obj *obj) +{ + int i; + int ret; + struct yaffsfs_Inode *in = NULL; + + if (obj) + obj = yaffs_get_equivalent_obj(obj); + + ret = yaffsfs_FindInodeIdForObject(obj); + + for (i = 0; i < YAFFSFS_N_HANDLES && ret < 0; i++) { + if (!yaffsfs_inode[i].iObj) + ret = i; + } + + if (ret >= 0) { + in = &yaffsfs_inode[ret]; + if (!in->iObj) + in->count = 0; + in->iObj = obj; + in->count++; + } + + return ret; +} + +static int yaffsfs_CountHandles(struct yaffs_obj *obj) +{ + int i = yaffsfs_FindInodeIdForObject(obj); + + if (i >= 0) + return yaffsfs_inode[i].count; + else + return 0; +} + +static void yaffsfs_ReleaseInode(struct yaffsfs_Inode *in) +{ + struct yaffs_obj *obj; + + obj = in->iObj; + + if (obj->unlinked) + yaffs_del_obj(obj); + + obj->my_inode = NULL; + in->iObj = NULL; + +} + +static void yaffsfs_PutInode(int inodeId) +{ + if (inodeId >= 0 && inodeId < YAFFSFS_N_HANDLES) { + struct yaffsfs_Inode *in = &yaffsfs_inode[inodeId]; + in->count--; + if (in->count <= 0) { + yaffsfs_ReleaseInode(in); + in->count = 0; + } + } +} + +static int yaffsfs_NewHandle(struct yaffsfs_Handle **hptr) +{ + int i; + struct yaffsfs_Handle *h; + + for (i = 0; i < YAFFSFS_N_HANDLES; i++) { + h = &yaffsfs_handle[i]; + if (h->useCount < 1) { + memset(h, 0, sizeof(struct yaffsfs_Handle)); + h->fdId = -1; + h->useCount = 1; + if (hptr) + *hptr = h; + return i; + } + } + return -1; +} + +static int yaffsfs_NewHandleAndFileDes(void) +{ + int i; + struct yaffsfs_FileDes *fd; + struct yaffsfs_Handle *h = NULL; + int handle = yaffsfs_NewHandle(&h); + + if (handle < 0) + return -1; + + for (i = 0; i < YAFFSFS_N_HANDLES; i++) { + fd = &yaffsfs_fd[i]; + if (fd->handleCount < 1) { + memset(fd, 0, sizeof(struct yaffsfs_FileDes)); + fd->inodeId = -1; + fd->handleCount = 1; + h->fdId = i; + return handle; + } + } + + /* Dump the handle because we could not get a fd */ + h->useCount = 0; + return -1; +} + +/* + * yaffs_get_handle + * Increase use of handle when reading/writing a file + * Also gets the file descriptor. + */ + +static int yaffsfs_GetHandle(int handle) +{ + struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); + + if (h && h->useCount > 0) { + h->useCount++; + return 0; + } + return -1; +} + +/* + * yaffs_put_handle + * Let go of a handle when closing a file or aborting an open or + * ending a read or write. + */ + +static int yaffsfs_PutFileDes(int fdId) +{ + struct yaffsfs_FileDes *fd; + + if (fdId >= 0 && fdId < YAFFSFS_N_HANDLES) { + fd = &yaffsfs_fd[fdId]; + fd->handleCount--; + if (fd->handleCount < 1) { + if (fd->inodeId >= 0) { + yaffsfs_PutInode(fd->inodeId); + fd->inodeId = -1; + } + } + } + return 0; +} + +static int yaffsfs_PutHandle(int handle) +{ + struct yaffsfs_Handle *h = yaffsfs_HandleToPointer(handle); + + if (h && h->useCount > 0) { + h->useCount--; + if (h->useCount < 1) { + yaffsfs_PutFileDes(h->fdId); + h->fdId = -1; + } + } + + return 0; +} + +static void yaffsfs_BreakDeviceHandles(struct yaffs_dev *dev) +{ + struct yaffsfs_FileDes *fd; + struct yaffsfs_Handle *h; + struct yaffs_obj *obj; + int i; + for (i = 0; i < YAFFSFS_N_HANDLES; i++) { + h = yaffsfs_HandleToPointer(i); + fd = yaffsfs_HandleToFileDes(i); + obj = yaffsfs_HandleToObject(i); + if (h && h->useCount > 0) { + h->useCount = 0; + h->fdId = 0; + } + if (fd && fd->handleCount > 0 && obj && obj->my_dev == dev) { + fd->handleCount = 0; + yaffsfs_PutInode(fd->inodeId); + fd->inodeId = -1; + } + } +} + +/* + * Stuff to handle names. + */ +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE + +static int yaffs_toupper(YCHAR a) +{ + if (a >= 'a' && a <= 'z') + return (a - 'a') + 'A'; + else + return a; +} + +static int yaffsfs_Match(YCHAR a, YCHAR b) +{ + return (yaffs_toupper(a) == yaffs_toupper(b)); +} +#else +static int yaffsfs_Match(YCHAR a, YCHAR b) +{ + /* case sensitive */ + return (a == b); +} +#endif + +static int yaffsfs_IsPathDivider(YCHAR ch) +{ + const YCHAR *str = YAFFS_PATH_DIVIDERS; + + while (*str) { + if (*str == ch) + return 1; + str++; + } + + return 0; +} + +static int yaffsfs_CheckNameLength(const char *name) +{ + int retVal = 0; + + int nameLength = yaffs_strnlen(name, YAFFS_MAX_NAME_LENGTH + 1); + + if (nameLength == 0) { + yaffsfs_SetError(-ENOENT); + retVal = -1; + } else if (nameLength > YAFFS_MAX_NAME_LENGTH) { + yaffsfs_SetError(-ENAMETOOLONG); + retVal = -1; + } + + return retVal; +} + +static int yaffsfs_alt_dir_path(const YCHAR *path, YCHAR **ret_path) +{ + YCHAR *alt_path = NULL; + int path_length; + int i; + + /* + * We don't have a definition for max path length. + * We will use 3 * max name length instead. + */ + *ret_path = NULL; + path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1); + + /* If the last character is a path divider, then we need to + * trim it back so that the name look-up works properly. + * eg. /foo/new_dir/ -> /foo/newdir + * Curveball: Need to handle multiple path dividers: + * eg. /foof/sdfse///// -> /foo/sdfse + */ + if (path_length > 0 && yaffsfs_IsPathDivider(path[path_length - 1])) { + alt_path = kmalloc(path_length + 1, 0); + if (!alt_path) + return -1; + yaffs_strcpy(alt_path, path); + for (i = path_length - 1; + i >= 0 && yaffsfs_IsPathDivider(alt_path[i]); i--) + alt_path[i] = (YCHAR) 0; + } + *ret_path = alt_path; + return 0; +} + +LIST_HEAD(yaffsfs_deviceList); + +/* + * yaffsfs_FindDevice + * yaffsfs_FindRoot + * Scan the configuration list to find the device + * Curveballs: Should match paths that end in '/' too + * Curveball2 Might have "/x/ and "/x/y". Need to return the longest match + */ +static struct yaffs_dev *yaffsfs_FindDevice(const YCHAR *path, + YCHAR **restOfPath) +{ + struct list_head *cfg; + const YCHAR *leftOver; + const YCHAR *p; + struct yaffs_dev *retval = NULL; + struct yaffs_dev *dev = NULL; + int thisMatchLength; + int longestMatch = -1; + int matching; + + /* + * Check all configs, choose the one that: + * 1) Actually matches a prefix (ie /a amd /abc will not match + * 2) Matches the longest. + */ + list_for_each(cfg, &yaffsfs_deviceList) { + dev = list_entry(cfg, struct yaffs_dev, dev_list); + leftOver = path; + p = dev->param.name; + thisMatchLength = 0; + matching = 1; + + while (matching && *p && *leftOver) { + /* Skip over any /s */ + while (yaffsfs_IsPathDivider(*p)) + p++; + + /* Skip over any /s */ + while (yaffsfs_IsPathDivider(*leftOver)) + leftOver++; + + /* Now match the text part */ + while (matching && + *p && !yaffsfs_IsPathDivider(*p) && + *leftOver && !yaffsfs_IsPathDivider(*leftOver)) { + if (yaffsfs_Match(*p, *leftOver)) { + p++; + leftOver++; + thisMatchLength++; + } else { + matching = 0; + } + } + } + + /* Skip over any /s in leftOver */ + while (yaffsfs_IsPathDivider(*leftOver)) + leftOver++; + + /*Skip over any /s in p */ + while (yaffsfs_IsPathDivider(*p)) + p++; + + /* p should now be at the end of the string if fully matched */ + if (*p) + matching = 0; + + if (matching && (thisMatchLength > longestMatch)) { + /* Matched prefix */ + *restOfPath = (YCHAR *) leftOver; + retval = dev; + longestMatch = thisMatchLength; + } + + } + return retval; +} + +static int yaffsfs_CheckPath(const YCHAR *path) +{ + int n = 0; + int divs = 0; + + while (*path && n < YAFFS_MAX_NAME_LENGTH && divs < 100) { + if (yaffsfs_IsPathDivider(*path)) { + n = 0; + divs++; + } else + n++; + path++; + } + + return (*path) ? -1 : 0; +} + +/* FindMountPoint only returns a dev entry if the path is a mount point */ +static struct yaffs_dev *yaffsfs_FindMountPoint(const YCHAR *path) +{ + struct yaffs_dev *dev; + YCHAR *restOfPath = NULL; + + dev = yaffsfs_FindDevice(path, &restOfPath); + if (dev && restOfPath && *restOfPath) + dev = NULL; + return dev; +} + +static struct yaffs_obj *yaffsfs_FindRoot(const YCHAR *path, + YCHAR **restOfPath) +{ + struct yaffs_dev *dev; + + dev = yaffsfs_FindDevice(path, restOfPath); + if (dev && dev->is_mounted) + return dev->root_dir; + + return NULL; +} + +static struct yaffs_obj *yaffsfs_FollowLink(struct yaffs_obj *obj, + int symDepth, int *loop) +{ + + if (obj) + obj = yaffs_get_equivalent_obj(obj); + + while (obj && obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) { + YCHAR *alias = obj->variant.symlink_variant.alias; + + if (yaffsfs_IsPathDivider(*alias)) + /* Starts with a /, need to scan from root up */ + obj = yaffsfs_FindObject(NULL, alias, symDepth++, + 1, NULL, NULL, loop); + else + /* + * Relative to here so use the parent of the + * symlink as a start + */ + obj = yaffsfs_FindObject(obj->parent, alias, symDepth++, + 1, NULL, NULL, loop); + } + return obj; +} + +/* + * yaffsfs_FindDirectory + * Parse a path to determine the directory and the name within the directory. + * + * eg. "/data/xx/ff" --> puts name="ff" and returns the directory "/data/xx" + */ +static struct yaffs_obj *yaffsfs_DoFindDirectory(struct yaffs_obj *startDir, + const YCHAR *path, + YCHAR **name, int symDepth, + int *notDir, int *loop) +{ + struct yaffs_obj *dir; + YCHAR *restOfPath; + YCHAR str[YAFFS_MAX_NAME_LENGTH + 1]; + int i; + + if (symDepth > YAFFSFS_MAX_SYMLINK_DEREFERENCES) { + if (loop) + *loop = 1; + return NULL; + } + + if (startDir) { + dir = startDir; + restOfPath = (YCHAR *) path; + } else + dir = yaffsfs_FindRoot(path, &restOfPath); + + while (dir) { + /* + * parse off /. + * curve ball: also throw away surplus '/' + * eg. "/ram/x////ff" gets treated the same as "/ram/x/ff" + */ + while (yaffsfs_IsPathDivider(*restOfPath)) + restOfPath++; /* get rid of '/' */ + + *name = restOfPath; + i = 0; + + while (*restOfPath && !yaffsfs_IsPathDivider(*restOfPath)) { + if (i < YAFFS_MAX_NAME_LENGTH) { + str[i] = *restOfPath; + str[i + 1] = '\0'; + i++; + } + restOfPath++; + } + + if (!*restOfPath) + /* got to the end of the string */ + return dir; + else { + if (yaffs_strcmp(str, _Y(".")) == 0) { + /* Do nothing */ + } else if (yaffs_strcmp(str, _Y("..")) == 0) { + dir = dir->parent; + } else { + dir = yaffs_find_by_name(dir, str); + + dir = yaffsfs_FollowLink(dir, symDepth, loop); + + if (dir && dir->variant_type != + YAFFS_OBJECT_TYPE_DIRECTORY) { + if (notDir) + *notDir = 1; + dir = NULL; + } + + } + } + } + /* directory did not exist. */ + return NULL; +} + +static struct yaffs_obj *yaffsfs_FindDirectory(struct yaffs_obj *relDir, + const YCHAR *path, + YCHAR **name, + int symDepth, + int *notDir, int *loop) +{ + return yaffsfs_DoFindDirectory(relDir, path, name, symDepth, notDir, + loop); +} + +/* + * yaffsfs_FindObject turns a path for an existing object into the object + */ +static struct yaffs_obj *yaffsfs_FindObject(struct yaffs_obj *relDir, + const YCHAR *path, int symDepth, + int getEquiv, + struct yaffs_obj **dirOut, + int *notDir, int *loop) +{ + struct yaffs_obj *dir; + struct yaffs_obj *obj; + YCHAR *name; + + dir = + yaffsfs_FindDirectory(relDir, path, &name, symDepth, notDir, loop); + + if (dirOut) + *dirOut = dir; + + if (dir && *name) + obj = yaffs_find_by_name(dir, name); + else + obj = dir; + + if (getEquiv) + obj = yaffs_get_equivalent_obj(obj); + + return obj; +} + +/************************************************************************* + * Start of yaffsfs visible functions. + *************************************************************************/ + +int yaffs_dup(int handle) +{ + int newHandleNumber = -1; + struct yaffsfs_FileDes *existingFD = NULL; + struct yaffsfs_Handle *existingHandle = NULL; + struct yaffsfs_Handle *newHandle = NULL; + + yaffsfs_Lock(); + existingHandle = yaffsfs_HandleToPointer(handle); + existingFD = yaffsfs_HandleToFileDes(handle); + if (existingFD) + newHandleNumber = yaffsfs_NewHandle(&newHandle); + if (newHandle) { + newHandle->fdId = existingHandle->fdId; + existingFD->handleCount++; + } + + yaffsfs_Unlock(); + + if (!existingFD) + yaffsfs_SetError(-EBADF); + else if (!newHandle) + yaffsfs_SetError(-ENOMEM); + + return newHandleNumber; + +} + +static int yaffsfs_TooManyObjects(struct yaffs_dev *dev) +{ + int current_objects = dev->n_obj - dev->n_deleted_files; + + if (dev->param.max_objects && current_objects > dev->param.max_objects) + return 1; + else + return 0; +} + +int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int sharing) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + YCHAR *name; + int handle = -1; + struct yaffsfs_FileDes *fd = NULL; + int openDenied = 0; + int symDepth = 0; + int errorReported = 0; + int rwflags = oflag & (O_RDWR | O_RDONLY | O_WRONLY); + u8 shareRead = (sharing & YAFFS_SHARE_READ) ? 1 : 0; + u8 shareWrite = (sharing & YAFFS_SHARE_WRITE) ? 1 : 0; + u8 sharedReadAllowed; + u8 sharedWriteAllowed; + u8 alreadyReading; + u8 alreadyWriting; + u8 readRequested; + u8 writeRequested; + int notDir = 0; + int loop = 0; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + /* O_EXCL only has meaning if O_CREAT is specified */ + if (!(oflag & O_CREAT)) + oflag &= ~(O_EXCL); + + /* O_TRUNC has no meaning if (O_CREAT | O_EXCL) is specified */ + if ((oflag & O_CREAT) & (oflag & O_EXCL)) + oflag &= ~(O_TRUNC); + + /* Todo: Are there any more flag combos to sanitise ? */ + + /* Figure out if reading or writing is requested */ + + readRequested = (rwflags == O_RDWR || rwflags == O_RDONLY) ? 1 : 0; + writeRequested = (rwflags == O_RDWR || rwflags == O_WRONLY) ? 1 : 0; + + yaffsfs_Lock(); + + handle = yaffsfs_NewHandleAndFileDes(); + + if (handle < 0) { + yaffsfs_SetError(-ENFILE); + errorReported = 1; + } else { + + fd = yaffsfs_HandleToFileDes(handle); + + /* try to find the exisiting object */ + obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL); + + obj = yaffsfs_FollowLink(obj, symDepth++, &loop); + + if (obj && + obj->variant_type != YAFFS_OBJECT_TYPE_FILE && + obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + obj = NULL; + + if (obj) { + + /* The file already exists or it might be a directory */ + + /* A directory can't be opened as a file */ + if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { + openDenied = 1; + yaffsfs_SetError(-EISDIR); + errorReported = 1; + } + + /* Open should fail if O_CREAT and O_EXCL are specified + * for a file that exists. + */ + if (!errorReported && + (oflag & O_EXCL) && (oflag & O_CREAT)) { + openDenied = 1; + yaffsfs_SetError(-EEXIST); + errorReported = 1; + } + + /* Check file permissions */ + if (readRequested && !(obj->yst_mode & S_IREAD)) + openDenied = 1; + + if (writeRequested && !(obj->yst_mode & S_IWRITE)) + openDenied = 1; + + if (!errorReported && writeRequested && + obj->my_dev->read_only) { + openDenied = 1; + yaffsfs_SetError(-EROFS); + errorReported = 1; + } + + if (openDenied && !errorReported) { + yaffsfs_SetError(-EACCES); + errorReported = 1; + } + + /* Check sharing of an existing object. */ + if (!openDenied) { + struct yaffsfs_FileDes *fdx; + int i; + + sharedReadAllowed = 1; + sharedWriteAllowed = 1; + alreadyReading = 0; + alreadyWriting = 0; + for (i = 0; i < YAFFSFS_N_HANDLES; i++) { + fdx = &yaffsfs_fd[i]; + if (fdx->handleCount > 0 && + fdx->inodeId >= 0 && + yaffsfs_inode[fdx->inodeId].iObj + == obj) { + if (!fdx->shareRead) + sharedReadAllowed = 0; + if (!fdx->shareWrite) + sharedWriteAllowed = 0; + if (fdx->reading) + alreadyReading = 1; + if (fdx->writing) + alreadyWriting = 1; + } + } + + if ((!sharedReadAllowed && readRequested) || + (!shareRead && alreadyReading) || + (!sharedWriteAllowed && writeRequested) || + (!shareWrite && alreadyWriting)) { + openDenied = 1; + yaffsfs_SetError(-EBUSY); + errorReported = 1; + } + } + + } + + /* If we could not open an existing object, then let's see if + * the directory exists. If not, error. + */ + if (!obj && !errorReported) { + dir = yaffsfs_FindDirectory(NULL, path, &name, 0, + ¬Dir, &loop); + if (!dir && notDir) { + yaffsfs_SetError(-ENOTDIR); + errorReported = 1; + } else if (loop) { + yaffsfs_SetError(-ELOOP); + errorReported = 1; + } else if (!dir) { + yaffsfs_SetError(-ENOENT); + errorReported = 1; + } + } + + if (!obj && dir && !errorReported && (oflag & O_CREAT)) { + /* Let's see if we can create this file */ + if (dir->my_dev->read_only) { + yaffsfs_SetError(-EROFS); + errorReported = 1; + } else if (yaffsfs_TooManyObjects(dir->my_dev)) { + yaffsfs_SetError(-ENFILE); + errorReported = 1; + } else + obj = yaffs_create_file(dir, name, mode, 0, 0); + + if (!obj && !errorReported) { + yaffsfs_SetError(-ENOSPC); + errorReported = 1; + } + } + + if (!obj && dir && !errorReported && !(oflag & O_CREAT)) { + yaffsfs_SetError(-ENOENT); + errorReported = 1; + } + + if (obj && !openDenied) { + int inodeId = yaffsfs_GetInodeIdForObject(obj); + + if (inodeId < 0) { + /* + * Todo: Fix any problem if inodes run out, + * That can't happen if the number of inode + * items >= number of handles. + */ + } + + fd->inodeId = inodeId; + fd->reading = readRequested; + fd->writing = writeRequested; + fd->append = (oflag & O_APPEND) ? 1 : 0; + fd->position = 0; + fd->shareRead = shareRead; + fd->shareWrite = shareWrite; + + /* Hook inode to object */ + obj->my_inode = (void *)&yaffsfs_inode[inodeId]; + + if ((oflag & O_TRUNC) && fd->writing) + yaffs_resize_file(obj, 0); + } else { + yaffsfs_PutHandle(handle); + if (!errorReported) + yaffsfs_SetError(0); /* Problem */ + handle = -1; + } + } + + yaffsfs_Unlock(); + + return handle; +} + +int yaffs_open(const YCHAR *path, int oflag, int mode) +{ + return yaffs_open_sharing(path, oflag, mode, + YAFFS_SHARE_READ | YAFFS_SHARE_WRITE); +} + +static int yaffs_Dofsync(int handle, int datasync) +{ + int retVal = -1; + struct yaffs_obj *obj; + + yaffsfs_Lock(); + + obj = yaffsfs_HandleToObject(handle); + + if (!obj) + yaffsfs_SetError(-EBADF); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else { + yaffs_flush_file(obj, 1, datasync); + retVal = 0; + } + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_fsync(int handle) +{ + return yaffs_Dofsync(handle, 0); +} + +int yaffs_flush(int handle) +{ + return yaffs_fsync(handle); +} + +int yaffs_fdatasync(int handle) +{ + return yaffs_Dofsync(handle, 1); +} + +int yaffs_close(int handle) +{ + struct yaffsfs_Handle *h = NULL; + struct yaffs_obj *obj = NULL; + int retVal = -1; + + yaffsfs_Lock(); + + h = yaffsfs_HandleToPointer(handle); + obj = yaffsfs_HandleToObject(handle); + + if (!h || !obj) + yaffsfs_SetError(-EBADF); + else { + /* clean up */ + yaffs_flush_file(obj, 1, 0); + yaffsfs_PutHandle(handle); + retVal = 0; + } + + yaffsfs_Unlock(); + + return retVal; +} + +static int yaffsfs_do_read(int handle, void *vbuf, unsigned int nbyte, + int isPread, Y_LOFF_T offset) +{ + struct yaffsfs_FileDes *fd = NULL; + struct yaffs_obj *obj = NULL; + Y_LOFF_T pos = 0; + Y_LOFF_T startPos = 0; + Y_LOFF_T endPos = 0; + int nRead = 0; + int nToRead = 0; + int totalRead = 0; + Y_LOFF_T maxRead; + u8 *buf = (u8 *) vbuf; + + if (!vbuf) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + fd = yaffsfs_HandleToFileDes(handle); + obj = yaffsfs_HandleToObject(handle); + + if (!fd || !obj) { + /* bad handle */ + yaffsfs_SetError(-EBADF); + totalRead = -1; + } else if (!fd->reading) { + /* Not a reading handle */ + yaffsfs_SetError(-EINVAL); + totalRead = -1; + } else if (nbyte > YAFFS_MAX_FILE_SIZE) { + yaffsfs_SetError(-EINVAL); + totalRead = -1; + } else { + if (isPread) + startPos = offset; + else + startPos = fd->position; + + pos = startPos; + + if (yaffs_get_obj_length(obj) > pos) + maxRead = yaffs_get_obj_length(obj) - pos; + else + maxRead = 0; + + if (nbyte > maxRead) + nbyte = maxRead; + + yaffsfs_GetHandle(handle); + + endPos = pos + nbyte; + + if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE || + nbyte > YAFFS_MAX_FILE_SIZE || + endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) { + totalRead = -1; + nbyte = 0; + } + + while (nbyte > 0) { + nToRead = YAFFSFS_RW_SIZE - + (pos & (YAFFSFS_RW_SIZE - 1)); + if (nToRead > nbyte) + nToRead = nbyte; + + /* Tricky bit... + * Need to reverify object in case the device was + * unmounted in another thread. + */ + obj = yaffsfs_HandleToObject(handle); + if (!obj) + nRead = 0; + else + nRead = yaffs_file_rd(obj, buf, pos, nToRead); + + if (nRead > 0) { + totalRead += nRead; + pos += nRead; + buf += nRead; + } + + if (nRead == nToRead) + nbyte -= nRead; + else + nbyte = 0; /* no more to read */ + + if (nbyte > 0) { + yaffsfs_Unlock(); + yaffsfs_Lock(); + } + + } + + yaffsfs_PutHandle(handle); + + if (!isPread) { + if (totalRead >= 0) + fd->position = startPos + totalRead; + else + yaffsfs_SetError(-EINVAL); + } + + } + + yaffsfs_Unlock(); + + return (totalRead >= 0) ? totalRead : -1; + +} + +int yaffs_read(int handle, void *buf, unsigned int nbyte) +{ + return yaffsfs_do_read(handle, buf, nbyte, 0, 0); +} + +int yaffs_pread(int handle, void *buf, unsigned int nbyte, Y_LOFF_T offset) +{ + return yaffsfs_do_read(handle, buf, nbyte, 1, offset); +} + +static int yaffsfs_do_write(int handle, const void *vbuf, unsigned int nbyte, + int isPwrite, Y_LOFF_T offset) +{ + struct yaffsfs_FileDes *fd = NULL; + struct yaffs_obj *obj = NULL; + Y_LOFF_T pos = 0; + Y_LOFF_T startPos = 0; + Y_LOFF_T endPos; + int nWritten = 0; + int totalWritten = 0; + int write_trhrough = 0; + int nToWrite = 0; + const u8 *buf = (const u8 *)vbuf; + + if (!vbuf) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + fd = yaffsfs_HandleToFileDes(handle); + obj = yaffsfs_HandleToObject(handle); + + if (!fd || !obj) { + /* bad handle */ + yaffsfs_SetError(-EBADF); + totalWritten = -1; + } else if (!fd->writing) { + yaffsfs_SetError(-EINVAL); + totalWritten = -1; + } else if (obj->my_dev->read_only) { + yaffsfs_SetError(-EROFS); + totalWritten = -1; + } else { + if (fd->append) + startPos = yaffs_get_obj_length(obj); + else if (isPwrite) + startPos = offset; + else + startPos = fd->position; + + yaffsfs_GetHandle(handle); + pos = startPos; + endPos = pos + nbyte; + + if (pos < 0 || pos > YAFFS_MAX_FILE_SIZE || + nbyte > YAFFS_MAX_FILE_SIZE || + endPos < 0 || endPos > YAFFS_MAX_FILE_SIZE) { + totalWritten = -1; + nbyte = 0; + } + + while (nbyte > 0) { + + nToWrite = YAFFSFS_RW_SIZE - + (pos & (YAFFSFS_RW_SIZE - 1)); + if (nToWrite > nbyte) + nToWrite = nbyte; + + /* Tricky bit... + * Need to reverify object in case the device was + * remounted or unmounted in another thread. + */ + obj = yaffsfs_HandleToObject(handle); + if (!obj || obj->my_dev->read_only) + nWritten = 0; + else + nWritten = + yaffs_wr_file(obj, buf, pos, nToWrite, + write_trhrough); + if (nWritten > 0) { + totalWritten += nWritten; + pos += nWritten; + buf += nWritten; + } + + if (nWritten == nToWrite) + nbyte -= nToWrite; + else + nbyte = 0; + + if (nWritten < 1 && totalWritten < 1) { + yaffsfs_SetError(-ENOSPC); + totalWritten = -1; + } + + if (nbyte > 0) { + yaffsfs_Unlock(); + yaffsfs_Lock(); + } + } + + yaffsfs_PutHandle(handle); + + if (!isPwrite) { + if (totalWritten > 0) + fd->position = startPos + totalWritten; + else + yaffsfs_SetError(-EINVAL); + } + } + + yaffsfs_Unlock(); + + return (totalWritten >= 0) ? totalWritten : -1; +} + +int yaffs_write(int fd, const void *buf, unsigned int nbyte) +{ + return yaffsfs_do_write(fd, buf, nbyte, 0, 0); +} + +int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, Y_LOFF_T offset) +{ + return yaffsfs_do_write(fd, buf, nbyte, 1, offset); +} + +int yaffs_truncate(const YCHAR *path, Y_LOFF_T new_size) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int result = YAFFS_FAIL; + int notDir = 0; + int loop = 0; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else if (obj->variant_type != YAFFS_OBJECT_TYPE_FILE) + yaffsfs_SetError(-EISDIR); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE) + yaffsfs_SetError(-EINVAL); + else + result = yaffs_resize_file(obj, new_size); + + yaffsfs_Unlock(); + + return (result) ? 0 : -1; +} + +int yaffs_ftruncate(int handle, Y_LOFF_T new_size) +{ + struct yaffsfs_FileDes *fd = NULL; + struct yaffs_obj *obj = NULL; + int result = 0; + + yaffsfs_Lock(); + fd = yaffsfs_HandleToFileDes(handle); + obj = yaffsfs_HandleToObject(handle); + + if (!fd || !obj) + /* bad handle */ + yaffsfs_SetError(-EBADF); + else if (!fd->writing) + yaffsfs_SetError(-EINVAL); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else if (new_size < 0 || new_size > YAFFS_MAX_FILE_SIZE) + yaffsfs_SetError(-EINVAL); + else + /* resize the file */ + result = yaffs_resize_file(obj, new_size); + yaffsfs_Unlock(); + + return (result) ? 0 : -1; + +} + +Y_LOFF_T yaffs_lseek(int handle, Y_LOFF_T offset, int whence) +{ + struct yaffsfs_FileDes *fd = NULL; + struct yaffs_obj *obj = NULL; + Y_LOFF_T pos = -1; + Y_LOFF_T fSize = -1; + + yaffsfs_Lock(); + fd = yaffsfs_HandleToFileDes(handle); + obj = yaffsfs_HandleToObject(handle); + + if (!fd || !obj) + yaffsfs_SetError(-EBADF); + else if (offset > YAFFS_MAX_FILE_SIZE) + yaffsfs_SetError(-EINVAL); + else { + if (whence == SEEK_SET) { + if (offset >= 0) + pos = offset; + } else if (whence == SEEK_CUR) { + if ((fd->position + offset) >= 0) + pos = (fd->position + offset); + } else if (whence == SEEK_END) { + fSize = yaffs_get_obj_length(obj); + if (fSize >= 0 && (fSize + offset) >= 0) + pos = fSize + offset; + } + + if (pos >= 0 && pos <= YAFFS_MAX_FILE_SIZE) + fd->position = pos; + else { + yaffsfs_SetError(-EINVAL); + pos = -1; + } + } + + yaffsfs_Unlock(); + + return pos; +} + +static int yaffsfs_DoUnlink(const YCHAR *path, int isDirectory) +{ + struct yaffs_obj *dir = NULL; + struct yaffs_obj *obj = NULL; + YCHAR *name; + int result = YAFFS_FAIL; + int notDir = 0; + int loop = 0; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 0, NULL, NULL, NULL); + dir = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir) + yaffsfs_SetError(-ENOENT); + else if (yaffs_strncmp(name, _Y("."), 2) == 0) + yaffsfs_SetError(-EINVAL); + else if (!obj) + yaffsfs_SetError(-ENOENT); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else if (!isDirectory && + obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) + yaffsfs_SetError(-EISDIR); + else if (isDirectory && + obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + yaffsfs_SetError(-ENOTDIR); + else if (isDirectory && obj == obj->my_dev->root_dir) + yaffsfs_SetError(-EBUSY); /* Can't rmdir a root */ + else { + result = yaffs_unlinker(dir, name); + + if (result == YAFFS_FAIL && isDirectory) + yaffsfs_SetError(-ENOTEMPTY); + } + + yaffsfs_Unlock(); + + return (result == YAFFS_FAIL) ? -1 : 0; +} + +int yaffs_unlink(const YCHAR *path) +{ + return yaffsfs_DoUnlink(path, 0); +} + +char* last_char_is(const char *s, int c) +{ + if (s && *s) + { + size_t sz = strlen(s) - 1; + s += sz; + if ( (unsigned char)*s == c) + return (char*)s; + } + + return NULL; +} + +#define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2]))) +char* concat_subpath_file(const char *path, const char *filename) +{ + YCHAR *new_path = NULL; + int path_length; + char *lc; + + if (filename && DOT_OR_DOTDOT(filename)) + return NULL; + + if (!path) + path = ""; + + /* + * We don't have a definition for max path length. + * We will use 3 * max name length instead. + */ + path_length = yaffs_strnlen(path, (YAFFS_MAX_NAME_LENGTH + 1) * 3 + 1); + new_path = kmalloc(path_length + 1, 0); + if(!new_path) + return NULL; + + memset(new_path, 0, path_length+1); + + lc = last_char_is(path, '/'); + while (*filename == '/') + filename++; + + sprintf(new_path, "%s%s%s", path, (lc==NULL ? "/" : ""), filename); + return new_path; +} + +/* Implement of ls by guowenxue, 2013.05.30 */ +int yaffs_ls(const char *dname, int recursive) +{ + yaffs_DIR *d; + struct yaffs_dirent *de; + struct yaffs_stat s; + char prefix[5]; + int rv = 0; + + memset(prefix, 0, sizeof(prefix)); + + if( ! (d=yaffs_opendir(dname)) ) + { + yaffs_trace(YAFFS_TRACE_ERROR, "Open '%s' failure: %s", dname, yaffs_perror()); + return -1; + } + + while((de = yaffs_readdir(d)) != NULL) + { + char *file_path; + file_path = concat_subpath_file(dname, de->d_name); + if( yaffs_lstat(file_path, &s) < 0) + { + yaffs_trace(YAFFS_TRACE_ERROR, "yaffs: Could not stat '%s'", file_path); + yaffs_set_error(-ENOENT); + rv = -1; + free(file_path); + break; + } + + /* Setup file mode */ + switch(s.st_mode & S_IFMT) + { + case S_IFREG: + prefix[0]='-'; + break; + case S_IFDIR: + prefix[0]='d'; + break; + case S_IFLNK: + prefix[0]='l'; + break; + default: + prefix[0]='u'; + break; + } + + /* Setup RWX mode */ + if(s.st_mode & S_IREAD) + prefix[1]='r'; + else + prefix[1]='-'; + + if(s.st_mode & S_IWRITE) + prefix[2]='w'; + else + prefix[2]='-'; + + if(s.st_mode & S_IEXEC) + prefix[3]='x'; + else + prefix[3]='-'; + + printf("%s %d %s %d bytes\n", prefix, s.st_nlink, file_path, (int)s.st_size); + if((s.st_mode & S_IFMT) == S_IFDIR && recursive) + { + yaffs_ls(file_path, recursive); + } + free(file_path); + } + + yaffs_closedir(d); + + //printf("Free space in %s is %d\n\n",dname,(int)yaffs_freespace(dname)); + return rv; +} + +/* Implement of rm -rf by guowenxue, 2013.05.30 */ +int yaffs_rm(const YCHAR *path, int recursive) +{ + struct yaffs_stat path_stat; + + if( yaffs_lstat(path, &path_stat) < 0) + { + yaffs_trace(YAFFS_TRACE_ERROR, "yaffs: Could not stat '%s'", path); + yaffs_set_error(-ENOENT); + return -1; + } + + if(S_ISDIR(path_stat.st_mode) ) + { + yaffs_DIR *dp = NULL; + struct yaffs_dirent *de = NULL; + + /* Only can remove empty folder */ + if( !recursive ) + return yaffs_rmdir(path); + + if ( ! (dp=yaffs_opendir(path)) ) + { + return -1; + } + + /* Remove all the file in current directory */ + while ((de = yaffs_readdir(dp)) != NULL) + { + char *new_path; + new_path = concat_subpath_file(path, de->d_name); + if (new_path == NULL) + continue; + + if (yaffs_rm(new_path, recursive) < 0) + { + free(new_path); + yaffs_closedir(dp); + return -1; + } + + free(new_path); + } + + /* Remove the left empty folder */ + yaffs_closedir(dp); + + if (yaffs_rmdir(path) < 0) + { + yaffs_trace(YAFFS_TRACE_ERROR, "can't remove '%s': %s", path, yaffs_perror()); + return -1; + } + + return 0; + } + + /* Not directory */ + return yaffs_unlink(path); +} + +int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) +{ + struct yaffs_obj *olddir = NULL; + struct yaffs_obj *newdir = NULL; + struct yaffs_obj *obj = NULL; + struct yaffs_obj *newobj = NULL; + YCHAR *oldname; + YCHAR *newname; + int result = YAFFS_FAIL; + int rename_allowed = 1; + int notOldDir = 0; + int notNewDir = 0; + int oldLoop = 0; + int newLoop = 0; + + YCHAR *alt_newpath = NULL; + + if (!oldPath || !newPath) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(oldPath) < 0 || yaffsfs_CheckPath(newPath) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + if (yaffsfs_alt_dir_path(newPath, &alt_newpath) < 0) { + yaffsfs_SetError(-ENOMEM); + return -1; + } + if (alt_newpath) + newPath = alt_newpath; + + yaffsfs_Lock(); + + olddir = yaffsfs_FindDirectory(NULL, oldPath, &oldname, 0, + ¬OldDir, &oldLoop); + newdir = yaffsfs_FindDirectory(NULL, newPath, &newname, 0, + ¬NewDir, &newLoop); + obj = yaffsfs_FindObject(NULL, oldPath, 0, 0, NULL, NULL, NULL); + newobj = yaffsfs_FindObject(NULL, newPath, 0, 0, NULL, NULL, NULL); + + /* If the object being renamed is a directory and the + * path ended with a "/" then the olddir == obj. + * We pass through NULL for the old name to tell the lower layers + * to use olddir as the object. + */ + + if (olddir == obj) + oldname = NULL; + + if ((!olddir && notOldDir) || (!newdir && notNewDir)) { + yaffsfs_SetError(-ENOTDIR); + rename_allowed = 0; + } else if (oldLoop || newLoop) { + yaffsfs_SetError(-ELOOP); + rename_allowed = 0; + } else if (olddir && oldname && + yaffs_strncmp(oldname, _Y("."), 2) == 0) { + yaffsfs_SetError(-EINVAL); + rename_allowed = 0; + } else if (!olddir || !newdir || !obj) { + yaffsfs_SetError(-ENOENT); + rename_allowed = 0; + } else if (obj->my_dev->read_only) { + yaffsfs_SetError(-EROFS); + rename_allowed = 0; + } else if (yaffs_is_non_empty_dir(newobj)) { + yaffsfs_SetError(-ENOTEMPTY); + rename_allowed = 0; + } else if (olddir->my_dev != newdir->my_dev) { + /* Rename must be on same device */ + yaffsfs_SetError(-EXDEV); + rename_allowed = 0; + } else if (obj && obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { + /* + * It is a directory, check that it is not being renamed to + * being its own decendent. + * Do this by tracing from the new directory back to the root, + * checking for obj + */ + + struct yaffs_obj *xx = newdir; + + while (rename_allowed && xx) { + if (xx == obj) + rename_allowed = 0; + xx = xx->parent; + } + if (!rename_allowed) + yaffsfs_SetError(-EINVAL); + } + + if (rename_allowed) + result = yaffs_rename_obj(olddir, oldname, newdir, newname); + + yaffsfs_Unlock(); + + kfree(alt_newpath); + + return (result == YAFFS_FAIL) ? -1 : 0; +} + +static int yaffsfs_DoStat(struct yaffs_obj *obj, struct yaffs_stat *buf) +{ + int retVal = -1; + + obj = yaffs_get_equivalent_obj(obj); + + if (obj && buf) { + buf->st_dev = (int)obj->my_dev->os_context; + buf->st_ino = obj->obj_id; + buf->st_mode = obj->yst_mode & ~S_IFMT; + + if (obj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) + buf->st_mode |= S_IFDIR; + else if (obj->variant_type == YAFFS_OBJECT_TYPE_SYMLINK) + buf->st_mode |= S_IFLNK; + else if (obj->variant_type == YAFFS_OBJECT_TYPE_FILE) + buf->st_mode |= S_IFREG; + + buf->st_nlink = yaffs_get_obj_link_count(obj); + buf->st_uid = 0; + buf->st_gid = 0; + buf->st_rdev = obj->yst_rdev; + buf->st_size = yaffs_get_obj_length(obj); + buf->st_blksize = obj->my_dev->data_bytes_per_chunk; + buf->st_blocks = (buf->st_size + buf->st_blksize - 1) / + buf->st_blksize; +#if CONFIG_YAFFS_WINCE + buf->yst_wince_atime[0] = obj->win_atime[0]; + buf->yst_wince_atime[1] = obj->win_atime[1]; + buf->yst_wince_ctime[0] = obj->win_ctime[0]; + buf->yst_wince_ctime[1] = obj->win_ctime[1]; + buf->yst_wince_mtime[0] = obj->win_mtime[0]; + buf->yst_wince_mtime[1] = obj->win_mtime[1]; +#else + buf->yst_atime = obj->yst_atime; + buf->yst_ctime = obj->yst_ctime; + buf->yst_mtime = obj->yst_mtime; +#endif + retVal = 0; + } + return retVal; +} + +static int yaffsfs_DoStatOrLStat(const YCHAR *path, + struct yaffs_stat *buf, int doLStat) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int retVal = -1; + int notDir = 0; + int loop = 0; + + if (!path || !buf) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + + if (!doLStat && obj) + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else + retVal = yaffsfs_DoStat(obj, buf); + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) +{ + return yaffsfs_DoStatOrLStat(path, buf, 0); +} + +int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) +{ + return yaffsfs_DoStatOrLStat(path, buf, 1); +} + +int yaffs_fstat(int fd, struct yaffs_stat *buf) +{ + struct yaffs_obj *obj; + + int retVal = -1; + + if (!buf) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (obj) + retVal = yaffsfs_DoStat(obj, buf); + else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +static int yaffsfs_DoUtime(struct yaffs_obj *obj, + const struct yaffs_utimbuf *buf) +{ + int retVal = -1; + int result; + + struct yaffs_utimbuf local; + + obj = yaffs_get_equivalent_obj(obj); + + if (obj && obj->my_dev->read_only) { + yaffsfs_SetError(-EROFS); + return -1; + } + + if (!buf) { + local.actime = Y_CURRENT_TIME; + local.modtime = local.actime; + buf = &local; + } + + if (obj) { + obj->yst_atime = buf->actime; + obj->yst_mtime = buf->modtime; + obj->dirty = 1; + result = yaffs_flush_file(obj, 0, 0); + retVal = result == YAFFS_OK ? 0 : -1; + } + + return retVal; +} + +int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int retVal = -1; + int notDir = 0; + int loop = 0; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else + retVal = yaffsfs_DoUtime(obj, buf); + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_futime(int fd, const struct yaffs_utimbuf *buf) +{ + struct yaffs_obj *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (obj) + retVal = yaffsfs_DoUtime(obj, buf); + else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +#ifndef CONFIG_YAFFS_WINCE +/* xattrib functions */ + +static int yaffs_do_setxattr(const YCHAR *path, const char *name, + const void *data, int size, int flags, int follow) +{ + struct yaffs_obj *obj; + struct yaffs_obj *dir; + int notDir = 0; + int loop = 0; + + int retVal = -1; + + if (!path || !name || !data) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + + if (follow) + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else { + retVal = yaffs_set_xattrib(obj, name, data, size, flags); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_setxattr(const YCHAR *path, const char *name, + const void *data, int size, int flags) +{ + return yaffs_do_setxattr(path, name, data, size, flags, 1); +} + +int yaffs_lsetxattr(const YCHAR *path, const char *name, + const void *data, int size, int flags) +{ + return yaffs_do_setxattr(path, name, data, size, flags, 0); +} + +int yaffs_fsetxattr(int fd, const char *name, + const void *data, int size, int flags) +{ + struct yaffs_obj *obj; + + int retVal = -1; + + if (!name || !data) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (!obj) + yaffsfs_SetError(-EBADF); + else { + retVal = yaffs_set_xattrib(obj, name, data, size, flags); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } + + yaffsfs_Unlock(); + + return retVal; +} + +static int yaffs_do_getxattr(const YCHAR *path, const char *name, + void *data, int size, int follow) +{ + struct yaffs_obj *obj; + struct yaffs_obj *dir; + int retVal = -1; + int notDir = 0; + int loop = 0; + + if (!path || !name || !data) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + + if (follow) + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else { + retVal = yaffs_get_xattrib(obj, name, data, size); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_getxattr(const YCHAR *path, const char *name, void *data, int size) +{ + return yaffs_do_getxattr(path, name, data, size, 1); +} + +int yaffs_lgetxattr(const YCHAR *path, const char *name, void *data, int size) +{ + return yaffs_do_getxattr(path, name, data, size, 0); +} + +int yaffs_fgetxattr(int fd, const char *name, void *data, int size) +{ + struct yaffs_obj *obj; + + int retVal = -1; + + if (!name || !data) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (obj) { + retVal = yaffs_get_xattrib(obj, name, data, size); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +static int yaffs_do_listxattr(const YCHAR *path, char *data, + int size, int follow) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int retVal = -1; + int notDir = 0; + int loop = 0; + + if (!path || !data) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + + if (follow) + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else { + retVal = yaffs_list_xattrib(obj, data, size); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_listxattr(const YCHAR *path, char *data, int size) +{ + return yaffs_do_listxattr(path, data, size, 1); +} + +int yaffs_llistxattr(const YCHAR *path, char *data, int size) +{ + return yaffs_do_listxattr(path, data, size, 0); +} + +int yaffs_flistxattr(int fd, char *data, int size) +{ + struct yaffs_obj *obj; + + int retVal = -1; + + if (!data) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (obj) { + retVal = yaffs_list_xattrib(obj, data, size); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +static int yaffs_do_removexattr(const YCHAR *path, const char *name, + int follow) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int notDir = 0; + int loop = 0; + int retVal = -1; + + if (!path || !name) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + + if (follow) + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else { + retVal = yaffs_remove_xattrib(obj, name); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_removexattr(const YCHAR *path, const char *name) +{ + return yaffs_do_removexattr(path, name, 1); +} + +int yaffs_lremovexattr(const YCHAR *path, const char *name) +{ + return yaffs_do_removexattr(path, name, 0); +} + +int yaffs_fremovexattr(int fd, const char *name) +{ + struct yaffs_obj *obj; + + int retVal = -1; + + if (!name) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (obj) { + retVal = yaffs_remove_xattrib(obj, name); + if (retVal < 0) { + yaffsfs_SetError(retVal); + retVal = -1; + } + } else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} +#endif + +#ifdef CONFIG_YAFFS_WINCE +int yaffs_get_wince_times(int fd, unsigned *wctime, + unsigned *watime, unsigned *wmtime) +{ + struct yaffs_obj *obj; + + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (obj) { + + if (wctime) { + wctime[0] = obj->win_ctime[0]; + wctime[1] = obj->win_ctime[1]; + } + if (watime) { + watime[0] = obj->win_atime[0]; + watime[1] = obj->win_atime[1]; + } + if (wmtime) { + wmtime[0] = obj->win_mtime[0]; + wmtime[1] = obj->win_mtime[1]; + } + + retVal = 0; + } else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_set_wince_times(int fd, + const unsigned *wctime, + const unsigned *watime, const unsigned *wmtime) +{ + struct yaffs_obj *obj; + int result; + int retVal = -1; + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (obj) { + + if (wctime) { + obj->win_ctime[0] = wctime[0]; + obj->win_ctime[1] = wctime[1]; + } + if (watime) { + obj->win_atime[0] = watime[0]; + obj->win_atime[1] = watime[1]; + } + if (wmtime) { + obj->win_mtime[0] = wmtime[0]; + obj->win_mtime[1] = wmtime[1]; + } + + obj->dirty = 1; + result = yaffs_flush_file(obj, 0, 0); + retVal = 0; + } else + /* bad handle */ + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; +} + +#endif + +static int yaffsfs_DoChMod(struct yaffs_obj *obj, mode_t mode) +{ + int result = -1; + + if (obj) + obj = yaffs_get_equivalent_obj(obj); + + if (obj) { + obj->yst_mode = mode; + obj->dirty = 1; + result = yaffs_flush_file(obj, 0, 0); + } + + return result == YAFFS_OK ? 0 : -1; +} + +int yaffs_access(const YCHAR *path, int amode) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int notDir = 0; + int loop = 0; + int retval = -1; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + if (amode & ~(R_OK | W_OK | X_OK)) { + yaffsfs_SetError(-EINVAL); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else if ((amode & W_OK) && obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else { + int access_ok = 1; + + if ((amode & R_OK) && !(obj->yst_mode & S_IREAD)) + access_ok = 0; + if ((amode & W_OK) && !(obj->yst_mode & S_IWRITE)) + access_ok = 0; + if ((amode & X_OK) && !(obj->yst_mode & S_IEXEC)) + access_ok = 0; + + if (!access_ok) + yaffsfs_SetError(-EACCES); + else + retval = 0; + } + + yaffsfs_Unlock(); + + return retval; + +} + +int yaffs_chmod(const YCHAR *path, mode_t mode) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int retVal = -1; + int notDir = 0; + int loop = 0; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + if (mode & ~(0777)) { + yaffsfs_SetError(-EINVAL); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + obj = yaffsfs_FollowLink(obj, 0, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else + retVal = yaffsfs_DoChMod(obj, mode); + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_fchmod(int fd, mode_t mode) +{ + struct yaffs_obj *obj; + int retVal = -1; + + if (mode & ~(0777)) { + yaffsfs_SetError(-EINVAL); + return -1; + } + + yaffsfs_Lock(); + obj = yaffsfs_HandleToObject(fd); + + if (!obj) + yaffsfs_SetError(-EBADF); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else + retVal = yaffsfs_DoChMod(obj, mode); + + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_mkdir(const YCHAR *path, mode_t mode) +{ + struct yaffs_obj *parent = NULL; + struct yaffs_obj *dir = NULL; + YCHAR *name; + YCHAR *alt_path = NULL; + int retVal = -1; + int notDir = 0; + int loop = 0; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + if (yaffsfs_alt_dir_path(path, &alt_path) < 0) { + yaffsfs_SetError(-ENOMEM); + return -1; + } + if (alt_path) + path = alt_path; + + yaffsfs_Lock(); + parent = yaffsfs_FindDirectory(NULL, path, &name, 0, ¬Dir, &loop); + if (!parent && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!parent) + yaffsfs_SetError(-ENOENT); + else if (yaffsfs_TooManyObjects(parent->my_dev)) + yaffsfs_SetError(-ENFILE); + else if (yaffs_strnlen(name, 5) == 0) { + /* Trying to make the root itself */ + yaffsfs_SetError(-EEXIST); + } else if (parent->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else { + dir = yaffs_create_dir(parent, name, mode, 0, 0); + if (dir) + retVal = 0; + else if (yaffs_find_by_name(parent, name)) + yaffsfs_SetError(-EEXIST); /* name exists */ + else + yaffsfs_SetError(-ENOSPC); /* assume no space */ + } + + yaffsfs_Unlock(); + + kfree(alt_path); + + return retVal; +} + +int yaffs_rmdir(const YCHAR *path) +{ + int result; + YCHAR *alt_path; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + if (yaffsfs_alt_dir_path(path, &alt_path) < 0) { + yaffsfs_SetError(-ENOMEM); + return -1; + } + if (alt_path) + path = alt_path; + result = yaffsfs_DoUnlink(path, 1); + + kfree(alt_path); + + return result; +} + +void *yaffs_getdev(const YCHAR *path) +{ + struct yaffs_dev *dev = NULL; + YCHAR *dummy; + dev = yaffsfs_FindDevice(path, &dummy); + return (void *)dev; +} + +int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt) +{ + int retVal = -1; + int result = YAFFS_FAIL; + struct yaffs_dev *dev = NULL; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffs_trace(YAFFS_TRACE_MOUNT, "yaffs: Mounting %s", path); + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + yaffsfs_InitHandles(); + + dev = yaffsfs_FindMountPoint(path); + if (dev) { + if (!dev->is_mounted) { + dev->read_only = read_only ? 1 : 0; + if (skip_checkpt) { + u8 skip = dev->param.skip_checkpt_rd; + dev->param.skip_checkpt_rd = 1; + result = yaffs_guts_initialise(dev); + dev->param.skip_checkpt_rd = skip; + } else { + result = yaffs_guts_initialise(dev); + } + + if (result == YAFFS_FAIL) + yaffsfs_SetError(-ENOMEM); + retVal = result ? 0 : -1; + + } else + yaffsfs_SetError(-EBUSY); + } else + yaffsfs_SetError(-ENODEV); + + yaffsfs_Unlock(); + return retVal; + +} + +int yaffs_mount2(const YCHAR *path, int readonly) +{ + return yaffs_mount_common(path, readonly, 0); +} + +int yaffs_mount(const YCHAR *path) +{ + return yaffs_mount_common(path, 0, 0); +} + +int yaffs_sync(const YCHAR *path) +{ + int retVal = -1; + struct yaffs_dev *dev = NULL; + YCHAR *dummy; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path, &dummy); + if (dev) { + if (!dev->is_mounted) + yaffsfs_SetError(-EINVAL); + else if (dev->read_only) + yaffsfs_SetError(-EROFS); + else { + + yaffs_flush_whole_cache(dev); + yaffs_checkpoint_save(dev); + retVal = 0; + + } + } else + yaffsfs_SetError(-ENODEV); + + yaffsfs_Unlock(); + return retVal; +} + +static int yaffsfs_IsDevBusy(struct yaffs_dev *dev) +{ + int i; + struct yaffs_obj *obj; + + for (i = 0; i < YAFFSFS_N_HANDLES; i++) { + obj = yaffsfs_HandleToObject(i); + if (obj && obj->my_dev == dev) + return 1; + } + return 0; +} + +int yaffs_remount(const YCHAR *path, int force, int read_only) +{ + int retVal = -1; + struct yaffs_dev *dev = NULL; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + dev = yaffsfs_FindMountPoint(path); + if (dev) { + if (dev->is_mounted) { + yaffs_flush_whole_cache(dev); + + if (force || !yaffsfs_IsDevBusy(dev)) { + if (read_only) + yaffs_checkpoint_save(dev); + dev->read_only = read_only ? 1 : 0; + retVal = 0; + } else + yaffsfs_SetError(-EBUSY); + + } else + yaffsfs_SetError(-EINVAL); + + } else + yaffsfs_SetError(-ENODEV); + + yaffsfs_Unlock(); + return retVal; + +} + +int yaffs_unmount2(const YCHAR *path, int force) +{ + int retVal = -1; + struct yaffs_dev *dev = NULL; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + dev = yaffsfs_FindMountPoint(path); + if (dev) { + if (dev->is_mounted) { + int inUse; + yaffs_flush_whole_cache(dev); + yaffs_checkpoint_save(dev); + inUse = yaffsfs_IsDevBusy(dev); + if (!inUse || force) { + if (inUse) + yaffsfs_BreakDeviceHandles(dev); + yaffs_deinitialise(dev); + + retVal = 0; + } else + yaffsfs_SetError(-EBUSY); + + } else + yaffsfs_SetError(-EINVAL); + + } else + yaffsfs_SetError(-ENODEV); + + yaffsfs_Unlock(); + return retVal; + +} + +int yaffs_unmount(const YCHAR *path) +{ + return yaffs_unmount2(path, 0); +} + +int yaffs_format(const YCHAR *path, + int unmount_flag, + int force_unmount_flag, + int remount_flag) +{ + int retVal = 0; + struct yaffs_dev *dev = NULL; + int result; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + dev = yaffsfs_FindMountPoint(path); + + if (dev) { + int was_mounted = dev->is_mounted; + + if (dev->is_mounted && unmount_flag) { + int inUse; + yaffs_flush_whole_cache(dev); + yaffs_checkpoint_save(dev); + inUse = yaffsfs_IsDevBusy(dev); + if (!inUse || force_unmount_flag) { + if (inUse) + yaffsfs_BreakDeviceHandles(dev); + yaffs_deinitialise(dev); + } + } + + if(dev->is_mounted) { + yaffsfs_SetError(-EBUSY); + retVal = -1; + } else { + yaffs_format_dev(dev); + if(was_mounted && remount_flag) { + result = yaffs_guts_initialise(dev); + if (result == YAFFS_FAIL) { + yaffsfs_SetError(-ENOMEM); + retVal = -1; + } + } + } + } else { + yaffsfs_SetError(-ENODEV); + retVal = -1; + } + + yaffsfs_Unlock(); + return retVal; + +} + + +Y_LOFF_T yaffs_freespace(const YCHAR *path) +{ + Y_LOFF_T retVal = -1; + struct yaffs_dev *dev = NULL; + YCHAR *dummy; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path, &dummy); + if (dev && dev->is_mounted) { + retVal = yaffs_get_n_free_chunks(dev); + retVal *= dev->data_bytes_per_chunk; + + } else + yaffsfs_SetError(-EINVAL); + + yaffsfs_Unlock(); + return retVal; +} + +Y_LOFF_T yaffs_totalspace(const YCHAR *path) +{ + Y_LOFF_T retVal = -1; + struct yaffs_dev *dev = NULL; + YCHAR *dummy; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path, &dummy); + if (dev && dev->is_mounted) { + retVal = (dev->param.end_block - dev->param.start_block + 1) - + dev->param.n_reserved_blocks; + retVal *= dev->param.chunks_per_block; + retVal *= dev->data_bytes_per_chunk; + + } else + yaffsfs_SetError(-EINVAL); + + yaffsfs_Unlock(); + return retVal; +} + +int yaffs_inodecount(const YCHAR *path) +{ + Y_LOFF_T retVal = -1; + struct yaffs_dev *dev = NULL; + YCHAR *dummy; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + dev = yaffsfs_FindDevice(path, &dummy); + if (dev && dev->is_mounted) { + int n_obj = dev->n_obj; + if (n_obj > dev->n_hardlinks) + retVal = n_obj - dev->n_hardlinks; + } + + if (retVal < 0) + yaffsfs_SetError(-EINVAL); + + yaffsfs_Unlock(); + return retVal; +} + +void yaffs_add_device(struct yaffs_dev *dev) +{ + struct list_head *cfg; + /* First check that the device is not in the list. */ + + list_for_each(cfg, &yaffsfs_deviceList) { + if (dev == list_entry(cfg, struct yaffs_dev, dev_list)) + return; + } + + dev->is_mounted = 0; + dev->param.remove_obj_fn = yaffsfs_RemoveObjectCallback; + + if (!dev->dev_list.next) + INIT_LIST_HEAD(&dev->dev_list); + + list_add(&dev->dev_list, &yaffsfs_deviceList); +} + +void yaffs_remove_device(struct yaffs_dev *dev) +{ + list_del_init(&dev->dev_list); +} + +/* Functions to iterate through devices. NB Use with extreme care! */ + +static struct list_head *dev_iterator; +void yaffs_dev_rewind(void) +{ + dev_iterator = yaffsfs_deviceList.next; +} + +struct yaffs_dev *yaffs_next_dev(void) +{ + struct yaffs_dev *retval; + + if (!dev_iterator) + return NULL; + if (dev_iterator == &yaffsfs_deviceList) + return NULL; + + retval = list_entry(dev_iterator, struct yaffs_dev, dev_list); + dev_iterator = dev_iterator->next; + return retval; +} + +/* Directory search stuff. */ + +static struct list_head search_contexts; + +static void yaffsfs_SetDirRewound(struct yaffsfs_DirSearchContxt *dsc) +{ + if (dsc && + dsc->dirObj && + dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { + + dsc->offset = 0; + + if (list_empty(&dsc->dirObj->variant.dir_variant.children)) + dsc->nextReturn = NULL; + else + dsc->nextReturn = + list_entry(dsc->dirObj->variant.dir_variant. + children.next, struct yaffs_obj, + siblings); + } else { + /* Hey someone isn't playing nice! */ + } +} + +static void yaffsfs_DirAdvance(struct yaffsfs_DirSearchContxt *dsc) +{ + if (dsc && + dsc->dirObj && + dsc->dirObj->variant_type == YAFFS_OBJECT_TYPE_DIRECTORY) { + + if (dsc->nextReturn == NULL || + list_empty(&dsc->dirObj->variant.dir_variant.children)) + dsc->nextReturn = NULL; + else { + struct list_head *next = dsc->nextReturn->siblings.next; + + if (next == &dsc->dirObj->variant.dir_variant.children) + dsc->nextReturn = NULL; /* end of list */ + else + dsc->nextReturn = list_entry(next, + struct yaffs_obj, + siblings); + } + } else { + /* Hey someone isn't playing nice! */ + } +} + +static void yaffsfs_RemoveObjectCallback(struct yaffs_obj *obj) +{ + + struct list_head *i; + struct yaffsfs_DirSearchContxt *dsc; + + /* if search contexts not initilised then skip */ + if (!search_contexts.next) + return; + + /* Iterate through the directory search contexts. + * If any are the one being removed, then advance the dsc to + * the next one to prevent a hanging ptr. + */ + list_for_each(i, &search_contexts) { + if (i) { + dsc = list_entry(i, struct yaffsfs_DirSearchContxt, + others); + if (dsc->nextReturn == obj) + yaffsfs_DirAdvance(dsc); + } + } + +} + +yaffs_DIR *yaffs_opendir(const YCHAR *dirname) +{ + yaffs_DIR *dir = NULL; + struct yaffs_obj *obj = NULL; + struct yaffsfs_DirSearchContxt *dsc = NULL; + int notDir = 0; + int loop = 0; + + if (!dirname) { + yaffsfs_SetError(-EFAULT); + return NULL; + } + + if (yaffsfs_CheckPath(dirname) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return NULL; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, dirname, 0, 1, NULL, ¬Dir, &loop); + + if (!obj && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!obj) + yaffsfs_SetError(-ENOENT); + else if (obj->variant_type != YAFFS_OBJECT_TYPE_DIRECTORY) + yaffsfs_SetError(-ENOTDIR); + else { + int i; + + for (i = 0, dsc = NULL; i < YAFFSFS_N_DSC && !dsc; i++) { + if (!yaffsfs_dsc[i].inUse) + dsc = &yaffsfs_dsc[i]; + } + + dir = (yaffs_DIR *) dsc; + + if (dsc) { + memset(dsc, 0, sizeof(struct yaffsfs_DirSearchContxt)); + dsc->inUse = 1; + dsc->dirObj = obj; + yaffs_strncpy(dsc->name, dirname, NAME_MAX); + INIT_LIST_HEAD(&dsc->others); + + if (!search_contexts.next) + INIT_LIST_HEAD(&search_contexts); + + list_add(&dsc->others, &search_contexts); + yaffsfs_SetDirRewound(dsc); + } + + } + + yaffsfs_Unlock(); + + return dir; +} + +struct yaffs_dirent *yaffs_readdir(yaffs_DIR * dirp) +{ + struct yaffsfs_DirSearchContxt *dsc; + struct yaffs_dirent *retVal = NULL; + + dsc = (struct yaffsfs_DirSearchContxt *) dirp; + yaffsfs_Lock(); + + if (dsc && dsc->inUse) { + yaffsfs_SetError(0); + if (dsc->nextReturn) { + dsc->de.d_ino = + yaffs_get_equivalent_obj(dsc->nextReturn)->obj_id; + dsc->de.d_dont_use = (unsigned)dsc->nextReturn; + dsc->de.d_off = dsc->offset++; + yaffs_get_obj_name(dsc->nextReturn, + dsc->de.d_name, NAME_MAX); + if (yaffs_strnlen(dsc->de.d_name, NAME_MAX + 1) == 0) { + /* this should not happen! */ + yaffs_strcpy(dsc->de.d_name, _Y("zz")); + } + dsc->de.d_reclen = sizeof(struct yaffs_dirent); + retVal = &dsc->de; + yaffsfs_DirAdvance(dsc); + } else + retVal = NULL; + } else + yaffsfs_SetError(-EBADF); + + yaffsfs_Unlock(); + + return retVal; + +} + +void yaffs_rewinddir(yaffs_DIR *dirp) +{ + struct yaffsfs_DirSearchContxt *dsc; + + dsc = (struct yaffsfs_DirSearchContxt *) dirp; + + yaffsfs_Lock(); + + yaffsfs_SetDirRewound(dsc); + + yaffsfs_Unlock(); +} + +int yaffs_closedir(yaffs_DIR *dirp) +{ + struct yaffsfs_DirSearchContxt *dsc; + + dsc = (struct yaffsfs_DirSearchContxt *) dirp; + + if (!dsc) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + dsc->inUse = 0; + list_del(&dsc->others); /* unhook from list */ + yaffsfs_Unlock(); + return 0; +} + +/* End of directory stuff */ + +int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath) +{ + struct yaffs_obj *parent = NULL; + struct yaffs_obj *obj; + YCHAR *name; + int retVal = -1; + int mode = 0; /* ignore for now */ + int notDir = 0; + int loop = 0; + + if (!oldpath || !newpath) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(newpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + parent = yaffsfs_FindDirectory(NULL, newpath, &name, 0, ¬Dir, &loop); + if (!parent && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!parent || yaffs_strnlen(name, 5) < 1) + yaffsfs_SetError(-ENOENT); + else if (yaffsfs_TooManyObjects(parent->my_dev)) + yaffsfs_SetError(-ENFILE); + else if (parent->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else if (parent) { + obj = yaffs_create_symlink(parent, name, mode, 0, 0, oldpath); + if (obj) + retVal = 0; + else if (yaffsfs_FindObject + (NULL, newpath, 0, 0, NULL, NULL, NULL)) + yaffsfs_SetError(-EEXIST); + else + yaffsfs_SetError(-ENOSPC); + } + + yaffsfs_Unlock(); + + return retVal; + +} + +int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz) +{ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *dir = NULL; + int retVal = -1; + int notDir = 0; + int loop = 0; + + if (!path || !buf) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, path, 0, 1, &dir, ¬Dir, &loop); + + if (!dir && notDir) + yaffsfs_SetError(-ENOTDIR); + else if (loop) + yaffsfs_SetError(-ELOOP); + else if (!dir || !obj) + yaffsfs_SetError(-ENOENT); + else if (obj->variant_type != YAFFS_OBJECT_TYPE_SYMLINK) + yaffsfs_SetError(-EINVAL); + else { + YCHAR *alias = obj->variant.symlink_variant.alias; + memset(buf, 0, bufsiz); + yaffs_strncpy(buf, alias, bufsiz - 1); + retVal = 0; + } + yaffsfs_Unlock(); + return retVal; +} + +int yaffs_link(const YCHAR *oldpath, const YCHAR *linkpath) +{ + /* Creates a link called newpath to existing oldpath */ + struct yaffs_obj *obj = NULL; + struct yaffs_obj *lnk = NULL; + struct yaffs_obj *obj_dir = NULL; + struct yaffs_obj *lnk_dir = NULL; + int retVal = -1; + int notDirObj = 0; + int notDirLnk = 0; + int objLoop = 0; + int lnkLoop = 0; + YCHAR *newname; + + if (!oldpath || !linkpath) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(linkpath) < 0 || yaffsfs_CheckPath(oldpath) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + yaffsfs_Lock(); + + obj = yaffsfs_FindObject(NULL, oldpath, 0, 1, + &obj_dir, ¬DirObj, &objLoop); + lnk = yaffsfs_FindObject(NULL, linkpath, 0, 0, NULL, NULL, NULL); + lnk_dir = yaffsfs_FindDirectory(NULL, linkpath, &newname, + 0, ¬DirLnk, &lnkLoop); + + if ((!obj_dir && notDirObj) || (!lnk_dir && notDirLnk)) + yaffsfs_SetError(-ENOTDIR); + else if (objLoop || lnkLoop) + yaffsfs_SetError(-ELOOP); + else if (!obj_dir || !lnk_dir || !obj) + yaffsfs_SetError(-ENOENT); + else if (obj->my_dev->read_only) + yaffsfs_SetError(-EROFS); + else if (yaffsfs_TooManyObjects(obj->my_dev)) + yaffsfs_SetError(-ENFILE); + else if (lnk) + yaffsfs_SetError(-EEXIST); + else if (lnk_dir->my_dev != obj->my_dev) + yaffsfs_SetError(-EXDEV); + else { + retVal = yaffsfs_CheckNameLength(newname); + + if (retVal == 0) { + lnk = yaffs_link_obj(lnk_dir, newname, obj); + if (lnk) + retVal = 0; + else { + yaffsfs_SetError(-ENOSPC); + retVal = -1; + } + } + } + yaffsfs_Unlock(); + + return retVal; +} + +int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev) +{ + (void) pathname; + (void) mode; + (void) dev; + + yaffsfs_SetError(-EINVAL); + return -1; +} + +/* + * D E B U G F U N C T I O N S + */ + +/* + * yaffs_n_handles() + * Returns number of handles attached to the object + */ +int yaffs_n_handles(const YCHAR *path) +{ + struct yaffs_obj *obj; + + if (!path) { + yaffsfs_SetError(-EFAULT); + return -1; + } + + if (yaffsfs_CheckPath(path) < 0) { + yaffsfs_SetError(-ENAMETOOLONG); + return -1; + } + + obj = yaffsfs_FindObject(NULL, path, 0, 1, NULL, NULL, NULL); + + if (obj) + return yaffsfs_CountHandles(obj); + else + return -1; +} + +int yaffs_get_error(void) +{ + return yaffsfs_GetLastError(); +} + +int yaffs_set_error(int error) +{ + yaffsfs_SetError(error); + return 0; +} + +int yaffs_dump_dev(const YCHAR *path) +{ +#if 1 + (void) path; +#else + YCHAR *rest; + + struct yaffs_obj *obj = yaffsfs_FindRoot(path, &rest); + + if (obj) { + struct yaffs_dev *dev = obj->my_dev; + + printf("\n" + "n_page_writes.......... %d\n" + "n_page_reads........... %d\n" + "n_erasures....... %d\n" + "n_gc_copies............ %d\n" + "garbageCollections... %d\n" + "passiveGarbageColl'ns %d\n" + "\n", + dev->n_page_writes, + dev->n_page_reads, + dev->n_erasures, + dev->n_gc_copies, + dev->garbageCollections, dev->passiveGarbageCollections); + + } +#endif + return 0; +} diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h new file mode 100644 index 0000000..334bb19 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yaffsfs.h @@ -0,0 +1,233 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * Header file for using yaffs in an application via + * a direct interface. + */ + + +#ifndef __YAFFSFS_H__ +#define __YAFFSFS_H__ + +#include "yaffscfg.h" +#include "yportenv.h" + + +#ifndef NAME_MAX +#define NAME_MAX 256 +#endif + +#define YAFFS_MAX_FILE_SIZE \ + ( (sizeof(Y_LOFF_T) < 8) ? YAFFS_MAX_FILE_SIZE_32 : (0x800000000LL - 1) ) + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +struct yaffs_dirent { + long d_ino; /* inode number */ + off_t d_off; /* offset to this dirent */ + unsigned short d_reclen; /* length of this dirent */ + YUCHAR d_type; /* type of this record */ + YCHAR d_name[NAME_MAX+1]; /* file name (null-terminated) */ + unsigned d_dont_use; /* debug: not for public consumption */ +}; + +typedef struct opaque_structure yaffs_DIR; + + + +struct yaffs_stat { + int st_dev; /* device */ + int st_ino; /* inode */ + unsigned st_mode; /* protection */ + int st_nlink; /* number of hard links */ + int st_uid; /* user ID of owner */ + int st_gid; /* group ID of owner */ + unsigned st_rdev; /* device type (if inode device) */ + Y_LOFF_T st_size; /* total size, in bytes */ + unsigned long st_blksize; /* blocksize for filesystem I/O */ + unsigned long st_blocks; /* number of blocks allocated */ +#ifdef CONFIG_YAFFS_WINCE + /* Special 64-bit times for WinCE */ + unsigned long yst_wince_atime[2]; + unsigned long yst_wince_mtime[2]; + unsigned long yst_wince_ctime[2]; +#else + unsigned long yst_atime; /* time of last access */ + unsigned long yst_mtime; /* time of last modification */ + unsigned long yst_ctime; /* time of last change */ +#endif +}; + + +struct yaffs_utimbuf { + unsigned long actime; + unsigned long modtime; +}; + + +int yaffs_open(const YCHAR *path, int oflag, int mode) ; + +int yaffs_close(int fd) ; +int yaffs_fsync(int fd) ; +int yaffs_fdatasync(int fd) ; +int yaffs_flush(int fd) ; /* same as yaffs_fsync() */ + +int yaffs_access(const YCHAR *path, int amode); + +int yaffs_dup(int fd); + +int yaffs_read(int fd, void *buf, unsigned int nbyte) ; +int yaffs_write(int fd, const void *buf, unsigned int nbyte) ; + +int yaffs_pread(int fd, void *buf, unsigned int nbyte, Y_LOFF_T offset); +int yaffs_pwrite(int fd, const void *buf, unsigned int nbyte, Y_LOFF_T offset); + +Y_LOFF_T yaffs_lseek(int fd, Y_LOFF_T offset, int whence) ; + +int yaffs_truncate(const YCHAR *path, Y_LOFF_T new_size); +int yaffs_ftruncate(int fd, Y_LOFF_T new_size); + +int yaffs_unlink(const YCHAR *path) ; +int yaffs_rm(const YCHAR *path, int recursive); /* Add by guowenxue, 2013.05.30 */ +int yaffs_ls(const char *dname, int recursive); /* Add by guowenxue, 2013.05.30 */ +int yaffs_rename(const YCHAR *oldPath, const YCHAR *newPath) ; + +int yaffs_stat(const YCHAR *path, struct yaffs_stat *buf) ; +int yaffs_lstat(const YCHAR *path, struct yaffs_stat *buf) ; +int yaffs_fstat(int fd, struct yaffs_stat *buf) ; + +int yaffs_utime(const YCHAR *path, const struct yaffs_utimbuf *buf); +int yaffs_futime(int fd, const struct yaffs_utimbuf *buf); + + +int yaffs_setxattr(const char *path, const char *name, + const void *data, int size, int flags); +int yaffs_lsetxattr(const char *path, const char *name, + const void *data, int size, int flags); +int yaffs_fsetxattr(int fd, const char *name, + const void *data, int size, int flags); + +int yaffs_getxattr(const char *path, const char *name, + void *data, int size); +int yaffs_lgetxattr(const char *path, const char *name, + void *data, int size); +int yaffs_fgetxattr(int fd, const char *name, + void *data, int size); + +int yaffs_removexattr(const char *path, const char *name); +int yaffs_lremovexattr(const char *path, const char *name); +int yaffs_fremovexattr(int fd, const char *name); + +int yaffs_listxattr(const char *path, char *list, int size); +int yaffs_llistxattr(const char *path, char *list, int size); +int yaffs_flistxattr(int fd, char *list, int size); + + +#ifdef CONFIG_YAFFS_WINCE + +int yaffs_set_wince_times(int fd, + const unsigned *wctime, + const unsigned *watime, + const unsigned *wmtime); +int yaffs_get_wince_times(int fd, + unsigned *wctime, + unsigned *watime, + unsigned *wmtime); + +#endif + +int yaffs_chmod(const YCHAR *path, mode_t mode); +int yaffs_fchmod(int fd, mode_t mode); + +int yaffs_mkdir(const YCHAR *path, mode_t mode) ; +int yaffs_rmdir(const YCHAR *path) ; + +yaffs_DIR *yaffs_opendir(const YCHAR *dirname) ; +struct yaffs_dirent *yaffs_readdir(yaffs_DIR *dirp) ; +void yaffs_rewinddir(yaffs_DIR *dirp) ; +int yaffs_closedir(yaffs_DIR *dirp) ; + +int yaffs_mount(const YCHAR *path) ; +int yaffs_mount2(const YCHAR *path, int read_only); +int yaffs_mount_common(const YCHAR *path, int read_only, int skip_checkpt); + +int yaffs_unmount(const YCHAR *path) ; +int yaffs_unmount2(const YCHAR *path, int force); +int yaffs_remount(const YCHAR *path, int force, int read_only); + +int yaffs_format(const YCHAR *path, + int unmount_flag, + int force_unmount_flag, + int remount_flag); + +int yaffs_sync(const YCHAR *path) ; + +int yaffs_symlink(const YCHAR *oldpath, const YCHAR *newpath); +int yaffs_readlink(const YCHAR *path, YCHAR *buf, int bufsiz); + +int yaffs_link(const YCHAR *oldpath, const YCHAR *newpath); +int yaffs_mknod(const YCHAR *pathname, mode_t mode, dev_t dev); + +Y_LOFF_T yaffs_freespace(const YCHAR *path); +Y_LOFF_T yaffs_totalspace(const YCHAR *path); + +int yaffs_inodecount(const YCHAR *path); + +int yaffs_n_handles(const YCHAR *path); + +#define YAFFS_SHARE_READ 1 +#define YAFFS_SHARE_WRITE 2 +int yaffs_open_sharing(const YCHAR *path, int oflag, int mode, int shareMode); + +struct yaffs_dev; +void yaffs_add_device(struct yaffs_dev *dev); + +int yaffs_start_up(void); +int yaffsfs_GetLastError(void); + +/* Functions to iterate through devices. NB Use with extreme care! */ +void yaffs_dev_rewind(void); +struct yaffs_dev *yaffs_next_dev(void); + +/* Function to get the last error */ +int yaffs_get_error(void); +const char *yaffs_error_to_str(int err); +static inline const char *yaffs_perror(void) /* Add by guowenxue, 2013.05.30 */ +{ + return yaffs_error_to_str(yaffs_get_error()); +} + +/* Function only for debugging */ +void *yaffs_getdev(const YCHAR *path); +int yaffs_dump_dev(const YCHAR *path); +int yaffs_set_error(int error); + +/* Trace control functions */ +unsigned yaffs_set_trace(unsigned tm); +unsigned yaffs_get_trace(void); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h b/linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h new file mode 100644 index 0000000..26efd7c --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/ydirectenv.h @@ -0,0 +1,99 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +/* + * ydirectenv.h: Environment wrappers for YAFFS direct. + */ + +#ifndef __YDIRECTENV_H__ +#define __YDIRECTENV_H__ + +#include "stdio.h" +#include "string.h" +#include "yaffs_osglue.h" +#include "yaffs_hweight.h" + +void yaffs_bug_fn(const char *file_name, int line_no); + +#define BUG() do { yaffs_bug_fn(__FILE__, __LINE__); } while (0) + + +#define YCHAR char +#define YUCHAR unsigned char +#define _Y(x) x + +#ifndef Y_LOFF_T +#define Y_LOFF_T loff_t +#endif + +#define yaffs_strcat(a, b) strcat(a, b) +#define yaffs_strcpy(a, b) strcpy(a, b) +#define yaffs_strncpy(a, b, c) strncpy(a, b, c) +#define yaffs_strnlen(s, m) strnlen(s, m) +#ifdef CONFIG_YAFFS_CASE_INSENSITIVE +#define yaffs_strcmp(a, b) strcasecmp(a, b) +#define yaffs_strncmp(a, b, c) strncasecmp(a, b, c) +#else +#define yaffs_strcmp(a, b) strcmp(a, b) +#define yaffs_strncmp(a, b, c) strncmp(a, b, c) +#endif + +#define hweight8(x) yaffs_hweight8(x) +#define hweight32(x) yaffs_hweight32(x) + +void yaffs_qsort(void *aa, size_t n, size_t es, + int (*cmp)(const void *, const void *)); + +#define sort(base, n, sz, cmp_fn, swp) yaffs_qsort(base, n, sz, cmp_fn) + +#define YAFFS_PATH_DIVIDERS "/" + +#ifdef NO_inline +#define inline +#else +#define inline __inline__ +#endif + +#define kmalloc(x, flags) yaffsfs_malloc(x) +#define kfree(x) yaffsfs_free(x) +#define vmalloc(x) yaffsfs_malloc(x) +#define vfree(x) yaffsfs_free(x) + +#define cond_resched() do {} while (0) + +#define yaffs_trace(msk, fmt, ...) do { \ + if (yaffs_trace_mask & (msk)) \ + printf("yaffs: " fmt "\n", ##__VA_ARGS__); \ +} while (0) + + +#define YAFFS_LOSTNFOUND_NAME "lost+found" +#define YAFFS_LOSTNFOUND_PREFIX "obj" + +#include "yaffscfg.h" + +#define Y_CURRENT_TIME yaffsfs_CurrentTime() +#define Y_TIME_CONVERT(x) x + +#define YAFFS_ROOT_MODE 0666 +#define YAFFS_LOSTNFOUND_MODE 0666 + +#include "yaffs_list.h" + +#include "yaffsfs.h" + +#endif + + diff --git a/linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h b/linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h new file mode 100644 index 0000000..194e0c8 --- /dev/null +++ b/linux-bsp/asm-study/yaffs2/yaffs2/yportenv.h @@ -0,0 +1,318 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning <charles@aleph1.co.uk> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + + +#ifndef __YPORTENV_H__ +#define __YPORTENV_H__ + +#include <stdio.h> +#include <string.h> +#include <types.h> +#include <malloc.h> + +#define CONFIG_YAFFS_DIRECT 1 /* Add by guowenxue */ +//#define CONFIG_YAFFS_DEFINES_TYPES 1 +#define CONFIG_YAFFS_PROVIDE_DEFS 1 +#define CONFIG_YAFFSFS_PROVIDE_VALUES 1 + + +/* Definition of types */ +#ifdef CONFIG_YAFFS_DEFINES_TYPES +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +#endif + + +#ifdef CONFIG_YAFFS_PROVIDE_DEFS +/* File types */ + + +#define DT_UNKNOWN 0 +#define DT_FIFO 1 +#define DT_CHR 2 +#define DT_DIR 4 +#define DT_BLK 6 +#define DT_REG 8 +#define DT_LNK 10 +#define DT_SOCK 12 +#define DT_WHT 14 + + +/* + * Attribute flags. + * These are or-ed together to select what has been changed. + */ +#define ATTR_MODE 1 +#define ATTR_UID 2 +#define ATTR_GID 4 +#define ATTR_SIZE 8 +#define ATTR_ATIME 16 +#define ATTR_MTIME 32 +#define ATTR_CTIME 64 + +struct iattr { + unsigned int ia_valid; + unsigned ia_mode; + unsigned ia_uid; + unsigned ia_gid; + unsigned ia_size; + unsigned ia_atime; + unsigned ia_mtime; + unsigned ia_ctime; + unsigned int ia_attr_flags; +}; + +#endif + + + +#if defined CONFIG_YAFFS_WINCE + +#include "ywinceenv.h" + + +#elif defined CONFIG_YAFFS_DIRECT + +/* Direct interface */ +#include "ydirectenv.h" + +#elif defined CONFIG_YAFFS_UTIL + +#include "yutilsenv.h" + +#else +/* Should have specified a configuration type */ +#error Unknown configuration + +#endif + +#if defined(CONFIG_YAFFS_DIRECT) || defined(CONFIG_YAFFS_WINCE) + +#ifdef CONFIG_YAFFSFS_PROVIDE_VALUES + +#ifndef O_RDONLY +#define O_RDONLY 00 +#endif + +#ifndef O_WRONLY +#define O_WRONLY 01 +#endif + +#ifndef O_RDWR +#define O_RDWR 02 +#endif + +#ifndef O_CREAT +#define O_CREAT 0100 +#endif + +#ifndef O_EXCL +#define O_EXCL 0200 +#endif + +#ifndef O_TRUNC +#define O_TRUNC 01000 +#endif + +#ifndef O_APPEND +#define O_APPEND 02000 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef EBUSY +#define EBUSY 16 +#endif + +#ifndef ENODEV +#define ENODEV 19 +#endif + +#ifndef EINVAL +#define EINVAL 22 +#endif + +#ifndef ENFILE +#define ENFILE 23 +#endif + +#ifndef EBADF +#define EBADF 9 +#endif + +#ifndef EACCES +#define EACCES 13 +#endif + +#ifndef EXDEV +#define EXDEV 18 +#endif + +#ifndef ENOENT +#define ENOENT 2 +#endif + +#ifndef ENOSPC +#define ENOSPC 28 +#endif + +#ifndef EROFS +#define EROFS 30 +#endif + +#ifndef ERANGE +#define ERANGE 34 +#endif + +#ifndef ENODATA +#define ENODATA 61 +#endif + +#ifndef ENOTEMPTY +#define ENOTEMPTY 39 +#endif + +#ifndef ENAMETOOLONG +#define ENAMETOOLONG 36 +#endif + +#ifndef ENOMEM +#define ENOMEM 12 +#endif + +#ifndef EFAULT +#define EFAULT 14 +#endif + +#ifndef EEXIST +#define EEXIST 17 +#endif + +#ifndef ENOTDIR +#define ENOTDIR 20 +#endif + +#ifndef EISDIR +#define EISDIR 21 +#endif + +#ifndef ELOOP +#define ELOOP 40 +#endif + + +/* Mode flags */ + +#ifndef S_IFMT +#define S_IFMT 0170000 +#endif + +#ifndef S_IFSOCK +#define S_IFSOCK 0140000 +#endif + +#ifndef S_IFIFO +#define S_IFIFO 0010000 +#endif + +#ifndef S_IFCHR +#define S_IFCHR 0020000 +#endif + +#ifndef S_IFBLK +#define S_IFBLK 0060000 +#endif + +#ifndef S_IFLNK +#define S_IFLNK 0120000 +#endif + +#ifndef S_IFDIR +#define S_IFDIR 0040000 +#endif + +#ifndef S_IFREG +#define S_IFREG 0100000 +#endif + +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) + + +#ifndef S_IREAD +#define S_IREAD 0000400 +#endif + +#ifndef S_IWRITE +#define S_IWRITE 0000200 +#endif + +#ifndef S_IEXEC +#define S_IEXEC 0000100 +#endif + +#ifndef XATTR_CREATE +#define XATTR_CREATE 1 +#endif + +#ifndef XATTR_REPLACE +#define XATTR_REPLACE 2 +#endif + +#ifndef R_OK +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 +#define F_OK 0 +#endif + +#else +#include <errno.h> +#include <sys/stat.h> +#include <fcntl.h> +#endif + +#endif + +#ifndef Y_DUMP_STACK +#define Y_DUMP_STACK() do { } while (0) +#endif + +#ifndef BUG +#define BUG() do {\ + yaffs_trace(YAFFS_TRACE_BUG,\ + "==>> yaffs bug: " __FILE__ " %d",\ + __LINE__);\ + Y_DUMP_STACK();\ +} while (0) +#endif + +#endif diff --git a/linux-bsp/bootstrap/bootstrap.S b/linux-bsp/bootstrap/bootstrap.S new file mode 100644 index 0000000..530fd1c --- /dev/null +++ b/linux-bsp/bootstrap/bootstrap.S @@ -0,0 +1,156 @@ + +/******************************************************************************************** + * File: bootstrap.S + * Version: 1.0.0 + * Copyright: 2011 (c) Guo Wenxue <Email: guowenxue@gmail.com QQ:281143292> + * Description: If we wanna debug u-boot by J-Link in external SDRAM, we must download this + * bootstrap.bin file into s3c24x0 8K internal SRAM(Stepping Stone) and excute + * first, which used to initialize the CPU and external SDRAM. Only after init + * the SDRAM then we can debug u-boot in it. + * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" + * + *******************************************************************************************/ + +#include "bootstrap.h" + + .text + .align 2 + .global _start + +_start: + /* set cpu to SVC32 mode */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0xd3 + msr cpsr, r0 + + /* Disable watchdog */ + ldr r0, =S3C_WATCHDOG_BASE + mov r1, #0 + str r1, [r0] + + /* Disable Interrupt */ + ldr r0, =S3C_INTERRUPT_BASE + mov r1, #0xffffffff + str r1, [r0, #INTMSK_OFFSET] + ldr r1, =0x000007ff + str r1, [r0, #INTSUBMSK_OFFSET] + + /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0290g/Babjcgjg.html */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache, Invalidate ICache and DCache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* disable MMU stuff and caches */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) + bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) + orr r0, r0, #0x00000002 @ set bit 2 (A) Align + orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache + mcr p15, 0, r0, c1, c0, 0 + + + /******************************************************************************************* + * Init system clock and power, FCLK:HCLK:PCLK = 1:4:8 + * Reference to S3C2440 datasheet: Chap 7 Clock&Power Management + * + * Initialize System Clock FCLK=400MHz HCLK=100MHz PCLK=50MHz + * FCLK is used by ARM920T + * HCLK is used for AHB bus, which is used by the ARM920T, the memory controller, + * the interrupt controller, the LCD controller, the DMA and USB host block. + * PCLK is is used for APB bus,which is used by the peripherals such as WDT,IIS,I2C, + * PWM timer,MMC interface,ADC,UART,GPIO,RTC and SPI. + ******************************************************************************************/ + + /*Set LOCKTIME as default value 0x00ffffff*/ + ldr r0, =S3C_CLOCK_POWER_BASE + ldr r1, =0x00ffffff + str r1, [r0, #LOCKTIME_OFFSET] + + /******************************************************************************************* + * Reference to S3C2440 datasheet: Chap 7-8 ~ Page 242 + * + * Set the selection of Dividing Ratio between FCLK,HCLK and PCLK as FCLK:HCLK:PCLK = 1:4:8. + * This ratio is determined by HDIVN(here is 2) and PDIVN(here is 1) control register. + * Refer to the s3c2440 datasheet + *******************************************************************************************/ + ldr r0, =S3C_CLOCK_POWER_BASE + mov r1, #5 + str r1, [r0, #CLKDIVN_OFFSET] /*Set Clock Divider*/ + + mrc p15, 0, r1, c1, c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 + + /*************************************************************************************** + * Reference to S3C2440 datasheet: Chap 7-20 ~ Page 254 + * + * Set MPLLCON(0x4C000004) register as: + * [19:12]: MDIV(Main Divider control)=0x7F (value set in MDIV_405) + * [9:4]: PDIV(Pre-devider control)=0x02 (value set in PSDIV_405) + * [1:0]: SDIV(Post divider control)=0x01 (value set in PSDIV_405) + * + * MPLL(FCLK) = (2 * m * Fin)/(p * 2^s) + * m=(MDIV+8), p=(PDIV+2), s=SDIV + * + * So FCLK=((2*(127+8)*Fin)) / ((2+2)*2^1) + * = (2*135*12MHz)/8 + * = 405MHz + * For FCLK:HCLK:PCLK=1:4:8, so HCLK=100MHz, PCLK=50MHz + ***************************************************************************************/ + mov r1, #S3C_CLOCK_POWER_BASE + mov r2, #MDIV_405 + add r2, r2, #PSDIV_405 + str r2, [r1, #MPLLCON_OFFSET] + +mem_init: + /* memory control configuration */ + /* make r0 relative the current location so that it */ + /* reads SMRDATA out of FLASH rather than memory ! */ + ldr r0, =SMRDATA + ldr r1, =mem_init + sub r0, r0, r1 + adr r3, mem_init /* r3 <- current position of code */ + add r0, r0, r3 /*r0 =SMRDATA-mem_init+mem_init =SMRDATA*/ + ldr r1, =BWSCON /* Bus Width Status Controller */ + add r2, r0, #13*4 +0: + ldr r3, [r0], #4 + str r3, [r1], #4 + cmp r2, r0 + bne 0b + + /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/ + ldr r0, =GPBCON + ldr r1, [r0] + bic r1, r1, #0xC00 /*Set GPBCON for GPIO5 as 0x00 */ + orr r1, r1, #0x0400 /*Set GPBCON for GPIO5 as GPIOOUT, 0x01*/ + str r1, [r0] + + ldr r3, [r2] + bic r3, r3, #(1<<LED0) /*Clear bit 5, set GPB5 as low level*/ + str r3, [r2] + + + /* everything is fine now */ +dead_loop: + b dead_loop + + .ltorg +/* the literal pools origin */ + +SMRDATA: + .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) + .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) + .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) + .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) + .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) + .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) + .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) + .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) + .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) + .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+REFCNT) + .word 0xb2 + .word 0x30 + .word 0x30 + diff --git a/linux-bsp/bootstrap/bootstrap.h b/linux-bsp/bootstrap/bootstrap.h new file mode 100644 index 0000000..1e85138 --- /dev/null +++ b/linux-bsp/bootstrap/bootstrap.h @@ -0,0 +1,148 @@ +/* + * ===================================================================================== + * + * Filename: bootstrap.h + * Version: 1.0.0 + * Author: Guo Wenxue<Email: guowenxue@ghlsystems.com QQ:281143292> + * CopyRight: 2011 (C) Guo Wenxue + * Description: Some Reigster address definition for bootstrap.S + * ===================================================================================== + */ + +#define S3C_WATCHDOG_BASE 0x53000000 + +#define S3C_INTERRUPT_BASE 0x4a000000 +#define SRCPND_OFFSET 0x00 +#define INTMOD_OFFSET 0x04 +#define INTMSK_OFFSET 0x08 +#define PRIORITY_OFFSET 0x0c +#define INTPND_OFFSET 0x10 +#define INTOFFSET_OFFSET 0x14 +#define SUBSRCPND_OFFSET 0x18 +#define INTSUBMSK_OFFSET 0x1c + +#define S3C_CLOCK_POWER_BASE 0x4c000000 +#define LOCKTIME_OFFSET 0x00 +#define MPLLCON_OFFSET 0x04 +#define UPLLCON_OFFSET 0x08 +#define CLKCON_OFFSET 0x0c +#define CLKSLOW_OFFSET 0x10 +#define CLKDIVN_OFFSET 0x14 +#define CAMDIVN_OFFSET 0x18 + +#define BWSCON 0x48000000 + +#define MDIV_405 0x7f << 12 +#define PSDIV_405 0x21 + + +#define GPBCON 0x56000010 +#define GPBDAT 0x56000014 +#define GPBUP 0x56000018 + +#define OUTPUT 0x01 /* Set GPIO port as output mode*/ +#define INPUT 0x00 /* Set GPIO port as input mode*/ + +#define BEEP 0 /* On FL2440 board, LED0 use GPB0*/ +#define LED0 5 /* On FL2440 board, LED0 use GPB5*/ +#define LED1 6 /* On FL2440 board, LED0 use GPB6*/ +#define LED2 8 /* On FL2440 board, LED0 use GPB8*/ +#define LED3 10 /* On FL2440 board, LED0 use GPB10*/ + +/* BWSCON */ +#define DW8 (0x0) +#define DW16 (0x1) +#define DW32 (0x2) +#define WAIT (0x1<<2) +#define UBLB (0x1<<3) + +#define B1_BWSCON (DW16) +#define B2_BWSCON (DW16) +#define B3_BWSCON (DW16 + WAIT + UBLB) +#define B4_BWSCON (DW16) +#define B5_BWSCON (DW16) +#define B6_BWSCON (DW32) +#define B7_BWSCON (DW32) + +#define B0_Tacs 0x0 +#define B0_Tcos 0x0 +#define B0_Tacc 0x7 +#define B0_Tcoh 0x0 +#define B0_Tah 0x0 +#define B0_Tacp 0x0 +#define B0_PMC 0x0 + +#define B1_Tacs 0x0 +#define B1_Tcos 0x0 +#define B1_Tacc 0x7 +#define B1_Tcoh 0x0 +#define B1_Tah 0x0 +#define B1_Tacp 0x0 +#define B1_PMC 0x0 + +#define B2_Tacs 0x0 +#define B2_Tcos 0x0 +#define B2_Tacc 0x7 +#define B2_Tcoh 0x0 +#define B2_Tah 0x0 +#define B2_Tacp 0x0 +#define B2_PMC 0x0 + +#define B3_Tacs 0xc +#define B3_Tcos 0x7 +#define B3_Tacc 0xf +#define B3_Tcoh 0x1 +#define B3_Tah 0x0 +#define B3_Tacp 0x0 +#define B3_PMC 0x0 + +#define B4_Tacs 0x0 +#define B4_Tcos 0x0 +#define B4_Tacc 0x7 +#define B4_Tcoh 0x0 +#define B4_Tah 0x0 +#define B4_Tacp 0x0 +#define B4_PMC 0x0 + +#define B5_Tacs 0xc +#define B5_Tcos 0x7 +#define B5_Tacc 0xf +#define B5_Tcoh 0x1 +#define B5_Tah 0x0 +#define B5_Tacp 0x0 +#define B5_PMC 0x0 + +/* SDRAM is on HSB bus, so its clock is from HCLK, FCLK=400, HCLK=100; so SDRAM 1clk=10ns */ + +#define B6_MT 0x3 /* SDRAM */ +// K4S561632 datasheet: RAS to CAS delay(Trcd) Min value should be 18/20ns, HCLK is 100MHz, so 1clk=10ns +// EM63A165 datasheet: RAS# to CAS# delay(Trcd) Min value should be 15/20ns, HCLK is 100MHz, so 1clk=10ns +#define B6_Trcd 0x2 /* 4clk */ +#define B6_SCAN 0x1 /* 9bit */ + +#define B7_MT 0x3 /* SDRAM */ +#define B7_Trcd 0x1 /* 3clk */ +#define B7_SCAN 0x1 /* 9bit */ + +/* REFRESH register<0x48000024> parameter */ +#define REFEN 0x1 /* Refresh enable */ +#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ + +// Trp: Row precharge time +// K4S561632 datasheet: Min(Trp) value should be 18/20ns; +// EM63A165 datasheet: Min value should be 15/20ns; +#define Trp 0x2 /* 4clk */ + +// Trc: Row cycle time +// K4S561632 datasheet: Min value should be 60/65ns; +// EM63A165 datasheet: Min value should be 60/63ns; +// S3C2440 datasheet: REFRESH register describe: SDRAM Row cycle time: Trc=Tsrc+Trp +#define Tsrc 0x2 /* 6clk, so Trc=Tsrc+Trp=6+3=9clk */ + +// K4S561632 datasheet: 64ms refresh period (8K Cycle): 64000/8192=7.81us +// EM63A165 datasheet: 8192 refresh cycles/64ms: 64000/8192=7.81us +// S3C2440 datasheet: REFRESH Register Refresh period = (2^11-refresh_count+1)/HCLK +// So Refresh count = 2^11 + 1 - 100x7.81 = 1268 +#define REFCNT 1268 +//#define REFCNT 489 /* HCLK=100Mhz, (2048+1-15.6*100) */ + diff --git a/linux-bsp/bootstrap/build.sh b/linux-bsp/bootstrap/build.sh new file mode 100755 index 0000000..b6be46b --- /dev/null +++ b/linux-bsp/bootstrap/build.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +BOARD=fl2440 +TFTP_PATH=/tftp +IMGS_PATH=../images +IMG_FILES=bootstrap-${BOARD}.bin + +CROSSTOOL=/opt/xtools/arm920t/bin/arm-linux- + +JOBS=`cat /proc/cpuinfo |grep "processor"|wc -l` + +set -e + +function do_clean() +{ + rm -f ${IMG_FILES} + rm -f cscope* tags + make clean +} + +function do_build() +{ + sed -i "s|^CROSS_COMPILE.*|CROSS_COMPILE\t?= ${CROSSTOOL}|g" makefile + make + cp bootstrap.bin ${IMG_FILES} +} + +function do_install() +{ + if [ -d $TFTP_PATH ] ;then + echo "cp ${IMG_FILES} $TFTP_PATH" + cp ${IMG_FILES} $TFTP_PATH + fi + + if [ -d ${IMGS_PATH} ] ; then + echo "cp ${IMG_FILES} $IMGS_PATH" + cp ${IMG_FILES} $IMGS_PATH + fi +} + +if [ "$1" == "clean" ] ; then + + do_clean + exit 0; + +fi + +do_build + +do_install + + diff --git a/linux-bsp/bootstrap/makefile b/linux-bsp/bootstrap/makefile new file mode 100644 index 0000000..93b294d --- /dev/null +++ b/linux-bsp/bootstrap/makefile @@ -0,0 +1,55 @@ +# *********************************************************************** +# * File: makefile +# * Version: 1.0.0 +# * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> +# * Description: Makefile used to cross compile the ASM and C source code +# * ChangeLog: 1, Release initial version on "Mon Mar 21 21:09:52 CST 2011" +# * +# *********************************************************************** + +BINAME = bootstrap +TEXTBASE = 0x33000000 +INST_PATH=${PWD}/../../../bin + +CROSS_COMPILE ?= /opt/xtools/arm920t/bin/arm-linux- +CC = $(CROSS_COMPILE)gcc +LD = $(CROSS_COMPILE)ld +AR = $(CROSS_COMPILE)ar +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +STRIP = $(CROSS_COMPILE)strip +READELF = $(CROSS_COMPILE)readelf + +CFLAGS = -g -O2 -Wall -nostdinc -nostdlib -fno-builtin +AFLAGS = $(CFLAGS) -D__ASSEMBLY__ + +LDFLAGS = -Ttext $(TEXTBASE) + +SRC_C = $(wildcard *.c) +SRC_S = $(wildcard *.S) +OBJ_C = $(patsubst %.c,%.o,$(SRC_C)) +OBJ_S = $(patsubst %.S,%.o,$(SRC_S)) + +OBJ_ALL = $(OBJ_C) $(OBJ_S) + +.PHONY : all +all: ${OBJ_ALL} + ${LD} $(LDFLAGS) -o ${BINAME}.elf ${OBJ_ALL} + ${OBJCOPY} -O binary -S ${BINAME}.elf ${BINAME}.bin + @rm -f *.elf *.o + make install + +%.o: %.S + $(CC) $(AFLAGS) -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +install: + cp -f ${BINAME}.bin ${INST_PATH} + +uninstall: + rm -f ${INST_PATH}/${BINAME}.bin + +clean: + @rm -f *.elf *.o + @rm -f ${BINAME}.bin diff --git a/linux-bsp/build.sh b/linux-bsp/build.sh new file mode 100755 index 0000000..1e9efae --- /dev/null +++ b/linux-bsp/build.sh @@ -0,0 +1,293 @@ +#!/bin/bash +# Description: This shell script used to build linux system SDK. You can +# use command line argument to specify build target, or select +# it by hand if no argument given by command line. More detail +# information can refer to the help message. +# +# Author: guowenxue <guowenxue@gmail.com> +# Version: 1.0.0 + + +PROJ_PATH=`pwd` + +CROSSTOOL=/opt/xtools/arm920t/bin/arm-linux- + +BOARD=fl2440 +PACK_PATH=${PROJ_PATH}/tarballs +PATCH_PATH=${PROJ_PATH}/patches +PATCH_SUFIX=${BOARD}.patch + +KERNEL_SRC=linux-3.0 +UBOOT_SRC=u-boot-2010.09 +BOOTSTRAP_SRC=bootstrap + +TARBALL_FTP=ftp://master.iot-yun.club/src/ + + +ROOTFS_SRC=rootfs +ROOTFS_IMG=rootfs-${BOARD}.ubi + +TFTP_PATH=/tftp +IMGS_PATH=images + +target= + +function show_help() +{ + printf "Usage: $1 [system/bootloader/kernel/rootfs/clean]\n\n" + + echo "system : build all source code " + echo "bootloader: build bootstrap and u-boot " + echo "kernel : build linux kernel " + echo "rootfs : build ubifs rootfs images" + printf "clean : clean the source code\n\n" + printf "distclean : remove all the source code\n\n" + + exit 0; +} + +function show_banner() +{ + echo "+---------------------------------------------+" + printf "$1\n" + echo "+---------------------------------------------+" +} + +function select_target() +{ + targets=("" "system" "bootloader" "kernel" "rootfs" "clean" "distclean") + echo "Please select a build target:" + echo "1 <system> , build all source code " + echo "2 <bootloader>, build bootstrap and u-boot " + echo "3 <kernel> , build linux kernel " + echo "4 <rootfs> , build ubifs rootfs image" + echo "5 <clean> , clean the source code" + echo "6 <distclean> , remove all the source code" + echo "" + + stty erase '^H' + read -p "Enter your choise [1-6] : " choice + + if [ $choice -gt 6 ] ; then + echo "ERROR: Invalid input choice, exit now..." + exit 1; + fi + + target=${targets[$choice]} +} + +function check_download_packet() +{ + if [ ! -f ${PACK_PATH}/${SRC_DIR}.tar.bz2 ] ; then + if [[ $SRC =~ bootstrap ]] ; then + return ; + else + show_banner "| start download $SRC_DIR packet |" + cd ${PACK_PATH}/ + wget ${TARBALL_FTP}/${SRC_DIR}.tar.bz2 + cd - + fi + fi +} + + +# Usage: start_build [SRCDIR: linux-3.0/bootstrap/u-boot-2010.09 ] + +function start_build() +{ + SRC_DIR=$1 + + if [ ! -d ${SRC_DIR} ] ; then + + check_download_packet ${SRC_DIR} + + show_banner "| start decompress $SRC_DIR packet |" + tar -xjf ${PACK_PATH}/${SRC_DIR}.tar.bz2 + cd ${SRC_DIR} + + # Copy u-boot logo file + echo ${SRC_DIR} | grep "u-boot" > /dev/null + if [ $? == 0 ] ; then + LOGO_FILE=logo-uboot.bmp + if [ -f ${PATCH_PATH}/${LOGO_FILE} ] ; then + cp -f ${PATCH_PATH}/${LOGO_FILE} tools/logos/logo.bmp + fi + fi + + # Copy linux kernel logo file + echo ${SRC_DIR} | grep "linux" > /dev/null + if [ $? == 0 ] ; then + LOGO_FILE=logo-kernel.ppm + if [ -f ${PATCH_PATH}/${LOGO_FILE} ] ; then + cp -f ${PATCH_PATH}/${LOGO_FILE} drivers/video/logo/logo_linux_clut224.ppm + fi + fi + + # patch for Jelliesv2 + if [ -f ${PATCH_PATH}/${SRC_DIR}-${PATCH_SUFIX} ] ; then + show_banner "| patch for ${SRC_DIR} |" + + # Only u-boot not update cross compiler + echo ${SRC_DIR} | grep "u-boot" > /dev/null + if [ $? != 0 ] ; then + sed -i -e "s|^+CROSSTOOL=.*|+CROSSTOOL=${CROSSTOOL}|g" ${PATCH_PATH}/${SRC_DIR}-${PATCH_SUFIX} + fi + patch -p1 < ${PATCH_PATH}/${SRC_DIR}-${PATCH_SUFIX} + fi + + else + cd ${SRC_DIR} + fi + + show_banner "| start $SRC_DIR build task... |" + chmod a+x build.sh + bash build.sh + show_banner "| $SRC_DIR build task over! |" + + cd - +} + +function build_ubifs() +{ + ubinize_cfg=ubinize.cfg + ubimg_tmp=ubi.img + + + # Rootfs partition size + partition_size=40 # MiB + + # K9F2G08: Nandflash 1 block=64 pages, 1 page = 2048 + BLOCK_PAGES=64 + PAGE_SIZE=2048 + + # Logic Erase Block Size: UBI requires 2 minimum I/O units out of each Physical Erase Block (PEB) for overhead: + # 1 for maintaining erase count information, and 1 for maintaining the Volume ID information. + + PEB_SIZE=`expr $PAGE_SIZE \* $BLOCK_PAGES` + LEB_SIZE=`expr $PEB_SIZE - 2 \* $PAGE_SIZE ` + + #UBI reserves 4 blocks space for management and bad PEB handling operations + # 2 PEBs are used to store the UBI volume table + # 1 PEB is reserved for wear-leveling purposes; + # 1 PEB is reserved for the atomic LEB change operation; + # a% of PEBs is reserved for handling bad EBs. The default for NAND is 1% + + PEB_CNT=`expr $partition_size \* 1024 \* 1024 / ${PEB_SIZE}` + LEB_CNT=`expr $PEB_CNT - 4 - $PEB_CNT \/ 100 ` + + #echo "Parition size ${partition_size}MiB and LEB=$LEB_CNT" + printf "\nWARNNING: generete rootfs image need root privilege, please input sudo passwd!\n\n" + set -x + sudo mkfs.ubifs -F -d ${ROOTFS_SRC} -m ${PAGE_SIZE} -e ${LEB_SIZE} -c $LEB_CNT -o ${ubimg_tmp} + set +x + + # vol_size smaller than the actual size of the partition to leave room for Ubifs internal data. + # With "vol_type=dynamic", Ubifs will end up using the whole space automatically + vol_size=`expr ${partition_size} \- 10` + + printf "[ubifs] \nmode=ubi \nimage=${ubimg_tmp} \nvol_id=0 \nvol_size=${vol_size}MiB\n" > $ubinize_cfg + printf "vol_type=dynamic \nvol_name=rootfs \nvol_flags=autoresize\n" >> $ubinize_cfg + #cat $ubinize_cfg + + set -x + ubinize -o ${ROOTFS_IMG} -m ${PAGE_SIZE} -p ${PEB_SIZE} $ubinize_cfg + set +x + + rm -f $ubimg_tmp $ubinize_cfg + chmod a+x ${ROOTFS_IMG} +} + +function build_rootfs() +{ + if [ ! -d ${ROOTFS_SRC} ] ; then + printf "\nWARNNING: decompress rootfs need root privilege, please input sudo passwd!\n\n" + sudo tar -xjf ${PACK_PATH}/${ROOTFS_SRC}.tar.bz2 + fi + + show_banner "| start build rootfs image... |" + build_ubifs + show_banner "| rootfs image build over! |" + + if [ -d ${IMGS_PATH} ] ; then + cp -f ${ROOTFS_IMG} ${IMGS_PATH} + fi + + if [ -d ${TFTP_PATH} ] ; then + cp -f ${ROOTFS_IMG} ${TFTP_PATH} + fi + + rm -f ${ROOTFS_IMG} + ls ${IMGS_PATH} +} + + +function do_clean() +{ + SRCS="$KERNEL_SRC $UBOOT_SRC $BOOTSTRAP_SRC" + + show_banner "| clean project source code |" + + for dir in $SRCS + do + if [ -d $dir ] ; then + cd $dir + bash build.sh clean + cd - + fi + done +} + +function do_distclean() +{ + if [ `id -u` != 0 ] ; then + printf "\nERROR: distclean need root privilege, please use sudo!\n\n" + exit ; + fi + + printf "\nWARNNING: Start remove all the source code and images\n\n" + rm -rf $KERNEL_SRC $UBOOT_SRC rootfs ${IMGS_PATH} +} + +function do_build() +{ + if [ "$target" = "system" ] ; then + start_build ${BOOTSTRAP_SRC} + start_build ${UBOOT_SRC} + start_build ${KERNEL_SRC} + build_rootfs + + elif [ "$target" = "bootloader" ] ; then + start_build ${BOOTSTRAP_SRC} + start_build ${UBOOT_SRC} + + elif [ "$target" = "kernel" ] ; then + start_build ${KERNEL_SRC} + + elif [ "$target" = "rootfs" ] ; then + build_rootfs + + elif [ "$target" = "clean" ] ; then + do_clean + + elif [ "$target" = "distclean" ] ; then + do_clean + do_distclean + + else + show_help + fi +} + +mkdir -p ${IMGS_PATH} + +# check input arguments for build target +if [ $# -ge 1 ] ; then + target=$1 +else + select_target +fi +show_banner "| choose build target [$target] |" + +do_build + + diff --git a/linux-bsp/driver/Makefile b/linux-bsp/driver/Makefile new file mode 100755 index 0000000..1fb8ad1 --- /dev/null +++ b/linux-bsp/driver/Makefile @@ -0,0 +1,46 @@ +#********************************************************************************* +# Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> +# All rights reserved. +# +# Filename: Makefile +# Description: This Makefile used to compile the driver for FL2440 +# +# Version: 1.0.0(10/08/2011~) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "11/11/2011 01:29:33 PM" +# +#********************************************************************************/ + +LINUX_SRC = ${shell pwd}/../linux/linux-3.0/ +CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- +INST_PATH=/tftp + +PWD := $(shell pwd) + +EXTRA_CFLAGS+=-DMODULE + +obj-m += kernel_hello.o +obj-m += s3c_led.o +obj-m += platdev_led.o +obj-m += platdrv_led.o +obj-m += platdrv_key.o + +modules: + @echo ${LINUX_SRC} + @make -C $(LINUX_SRC) M=$(PWD) modules + @make clear + +uninstall: + rm -f ${INST_PATH}/*.ko + +install: uninstall + cp -af *.ko ${INST_PATH} + +clear: + @rm -f *.o *.cmd *.mod.c + @rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f + @rm -f .*ko.cmd .*.o.cmd .*.o.d + +clean: clear + @rm -f *.ko + diff --git a/linux-bsp/driver/kernel_hello.c b/linux-bsp/driver/kernel_hello.c new file mode 100644 index 0000000..a5c8d25 --- /dev/null +++ b/linux-bsp/driver/kernel_hello.c @@ -0,0 +1,35 @@ +/********************************************************************************* + * Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> + * All rights reserved. + * + * Filename: kernel_hello.c + * Description: This file is the linux kernel module sample + * + * Version: 1.0.0(03/16/2013~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "03/16/2013 10:50:26 AM" + * + ********************************************************************************/ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> + +static __init int hello_init(void) +{ + printk(KERN_ALERT "Hello, LingYun IoT Studio!\n"); + return 0; +} + +static __exit void hello_exit(void) +{ + printk(KERN_ALERT "Goodbye, I have found a good job!\n"); +} + +module_init(hello_init); +module_exit(hello_exit); + +MODULE_AUTHOR("GuoWenxue <guowenxue@gmail.com>"); +MODULE_DESCRIPTION("Linux Kernel hello module (C) LingYun IoT Studio"); +MODULE_LICENSE("Dual BSD/GPL"); + diff --git a/linux-bsp/driver/platdev_led.c b/linux-bsp/driver/platdev_led.c new file mode 100644 index 0000000..aa864a7 --- /dev/null +++ b/linux-bsp/driver/platdev_led.c @@ -0,0 +1,111 @@ +/********************************************************************************* + * Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> + * All rights reserved. + * + * Filename: platdev_led.c + * Description: This is the LED platform device + * + * Version: 1.0.0(10/27/2011~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/27/2011 11:39:10 AM" + * + ********************************************************************************/ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> + +#include "platdev_led.h" + +/* LED hardware informtation data*/ +static struct s3c_led_info s3c_leds[] = { + [0] = { + .num = 1, + .gpio = S3C2410_GPB(5), + .active_level = LOWLEVEL, + .status = OFF, + .blink = ENABLE, + }, + [1] = { + .num = 2, + .gpio = S3C2410_GPB(6), + .active_level = LOWLEVEL, + .status = OFF, + .blink = DISABLE, + }, + [2] = { + .num = 3, + .gpio = S3C2410_GPB(8), + .active_level = LOWLEVEL, + .status = OFF, + .blink = DISABLE, + }, + [3] = { + .num = 4, + .gpio = S3C2410_GPB(10), + .active_level = LOWLEVEL, + .status = OFF, + .blink = DISABLE, + }, +}; + +/* The LED platform device private data */ +static struct s3c_led_platform_data s3c_led_data = { + .leds = s3c_leds, + .nleds = ARRAY_SIZE(s3c_leds), +}; + + +static void platform_led_release(struct device * dev) +{ + int i; + struct s3c_led_platform_data *pdata = dev->platform_data; + + for(i=0; i<pdata->nleds; i++) + { + /* Turn all LED off */ + s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); + } +} + +static struct platform_device s3c_led_device = { + .name = "s3c_led", + .id = 1, + .dev = + { + .platform_data = &s3c_led_data, + .release = platform_led_release, + }, +}; + + +static int __init platdev_led_init(void) +{ + int rv = 0; + + rv = platform_device_register(&s3c_led_device); + if(rv) + { + printk(KERN_ERR "%s:%d: Can't register platform device %d\n", __FUNCTION__,__LINE__, rv); + return rv; + } + printk("Regist S3C LED Platform Device successfully.\n"); + + return 0; +} + + +static void platdev_led_exit(void) +{ + printk("%s():%d remove LED platform device\n", __FUNCTION__,__LINE__); + platform_device_unregister(&s3c_led_device); +} + +module_init(platdev_led_init); +module_exit(platdev_led_exit); + +MODULE_AUTHOR("GuoWenxue<guowenxue@gmail.com>"); +MODULE_DESCRIPTION("FL2440 LED driver platform device"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s3c_platdev_led"); + + diff --git a/linux-bsp/driver/platdev_led.h b/linux-bsp/driver/platdev_led.h new file mode 100644 index 0000000..a1a86f7 --- /dev/null +++ b/linux-bsp/driver/platdev_led.h @@ -0,0 +1,67 @@ +/********************************************************************************* + * Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> + * All rights reserved. + * + * Filename: platdev_led.h + * Description: This is the LED platform device head file + * + * Version: 1.0.0(10/27/2011~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/27/2011 11:39:10 AM" + * + ********************************************************************************/ + +#ifndef _PLATDEV_LED_H_ +#define _PLATDEV_LED_H_ + +#include <linux/platform_device.h> +#include <linux/version.h> + +#include <mach/regs-gpio.h> + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) +#include <mach/hardware.h> +#include <mach/gpio.h> +#include <asm/irq.h> +#else +#include <asm-arm/irq.h> +#include <asm/arch/gpio.h> +#include <asm/arch/hardware.h> +#endif + + + +#define ENPULLUP 1 +#define DISPULLUP 0 + +#define HIGHLEVEL 1 +#define LOWLEVEL 0 + +#define INPUT 1 +#define OUTPUT 0 + +#define OFF 0 +#define ON 1 + +#define ENABLE 1 +#define DISABLE 0 + +/* LED hardware informtation structure*/ +struct s3c_led_info +{ + unsigned char num; /* The LED number */ + unsigned int gpio; /* Which GPIO the LED used */ + unsigned char active_level; /* The GPIO pin level(HIGHLEVEL or LOWLEVEL) to turn on or off */ + unsigned char status; /* Current LED status: OFF/ON */ + unsigned char blink; /* Blink or not */ +}; + +/* The LED platform device private data structure */ +struct s3c_led_platform_data +{ + struct s3c_led_info *leds; + int nleds; +}; + + +#endif /* ----- #ifndef _PLATDEV_LED_H_ ----- */ diff --git a/linux-bsp/driver/platdrv_key.c b/linux-bsp/driver/platdrv_key.c new file mode 100644 index 0000000..cdc39f0 --- /dev/null +++ b/linux-bsp/driver/platdrv_key.c @@ -0,0 +1,339 @@ +/********************************************************************************* + * Copyright: (C) 2016 Guo Wenxue<guowenxue@aliyun.com> + * All rights reserved. + * + * Filename: platdev_key.c + * Description: This file is the keypad platform driver + * + * Version: 1.0.0(07/26/2016) + * Author: Guo Wenxue <guowenxue@aliyun.com> + * ChangeLog: 1, Release initial version on "07/26/2016 05:01:25 PM" + * + ********************************************************************************/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/input.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <mach/hardware.h> +#include <asm/gpio.h> +#include <asm/irq.h> +#include <linux/slab.h> +#include <mach/regs-gpio.h> + +/* 1HZ=100*jiffies 1*jiffies=10ms => 1HZ=100*10ms = 1s */ +#define CANCEL_DITHERING_DELAY (HZ/50) /* Remove button push down dithering timer delay 20ms */ + + +/*+------------------------------------------------+ + | keyboard platform device information | + +------------------------------------------------+*/ + +/* keyboard hardware informtation structure definition */ +typedef struct s3c_kbd_info_s +{ + int code; /* input device key code */ + int nIRQ; /* keyboard IRQ number*/ + unsigned int setting; /* keyboard IRQ Pin Setting*/ + unsigned int gpio; /* keyboard GPIO port */ +} s3c_kbd_info_t; + +/* keyboard platform device private data structure */ +typedef struct s3c_kbd_platform_data_s +{ + s3c_kbd_info_t *keys; + int nkeys; +} s3c_kbd_platform_data_t; + + +static s3c_kbd_info_t s3c_kbd_gpios[] = { + [0] = { + .code = KEY_1, + .nIRQ = IRQ_EINT0, + .gpio = S3C2410_GPF(0), + .setting = S3C2410_GPF0_EINT0, + }, + [1] = { + .code = KEY_2, + .nIRQ = IRQ_EINT2, + .gpio = S3C2410_GPF(2), + .setting = S3C2410_GPF2_EINT2, + }, + [2] = { + .code = KEY_3, + .nIRQ = IRQ_EINT3, + .gpio = S3C2410_GPF(3), + .setting = S3C2410_GPF3_EINT3, + }, + [3] = { + .code = KEY_4, + .nIRQ = IRQ_EINT4, + .gpio = S3C2410_GPF(4), + .setting = S3C2410_GPF4_EINT4, + }, +}; + +/* keyboard platform device private data */ +static s3c_kbd_platform_data_t s3c_kbd_data = { + .keys = s3c_kbd_gpios, + .nkeys = ARRAY_SIZE(s3c_kbd_gpios), +}; + +static void platform_kbd_release(struct device * dev) +{ + return; +} + +static struct platform_device s3c_keyboard_device = { + .name = "s3c_kbd", + .id = 1, + .dev = + { + .platform_data = &s3c_kbd_data, + .release = platform_kbd_release, + }, +}; + + +/*+------------------------------------------------+ + | keyboard platform driver information | + +------------------------------------------------+*/ + +typedef struct s3c_kbd_s +{ + struct timer_list *timers; /* every key get a cancel dithering timer */ + struct input_dev *input_dev; + s3c_kbd_platform_data_t *pdata; +} s3c_kbd_t; /*--- end of struct s3c_kbd_s ---*/ + + +s3c_kbd_t *s3c_kbd = NULL; + +static irqreturn_t s3c_kbd_intterupt(int irq, void *dev_id) +{ + int i; + int found = 0; + struct platform_device *pdev = dev_id; + s3c_kbd_t *s3c_kbd = NULL; + + s3c_kbd = platform_get_drvdata(pdev); + + for(i=0; i<s3c_kbd->pdata->nkeys; i++) + { + if(irq == s3c_kbd->pdata->keys[i].nIRQ) + { + found = 1; + break; + } + } + + if(!found) /* An ERROR interrupt */ + return IRQ_NONE; + + mod_timer(&s3c_kbd->timers[i], jiffies+CANCEL_DITHERING_DELAY); + return IRQ_HANDLED; +} + +static void cancel_dithering_timer_handler(unsigned long data) +{ + int which =(int)data; + unsigned int pinval; + + pinval = s3c2410_gpio_getpin(s3c_kbd->pdata->keys[which].gpio); + + if( pinval ) + { + //printk("s3c_kbd key[%d] code[%d] released\n", which, s3c_kbd->pdata->keys[which].code); + input_event(s3c_kbd->input_dev, EV_KEY, s3c_kbd->pdata->keys[which].code, 0); + } + else + { + //printk("s3c_kbd key[%d] code[%d] pressed\n", which, s3c_kbd->pdata->keys[which].code); + input_event(s3c_kbd->input_dev, EV_KEY, s3c_kbd->pdata->keys[which].code, 1); + } + + input_sync(s3c_kbd->input_dev); +} + +static int s3c_kbd_probe(struct platform_device *pdev) +{ + int i = 0; + int rv = -ENOMEM; + struct input_dev *input_dev = NULL; + s3c_kbd_platform_data_t *pdata = pdev->dev.platform_data; + + /* malloc s3c_kbd struct */ + s3c_kbd = kmalloc(sizeof(s3c_kbd_t), GFP_KERNEL); + if( !s3c_kbd ) + { + printk("error: s3c_kbd_probe kmalloc() for s3c_kbd failure\n"); + goto fail; + } + memset(s3c_kbd, 0, sizeof(s3c_kbd_t)); + + /* malloc cancel dithering timer for every key */ + s3c_kbd->timers = (struct timer_list *) kmalloc(pdata->nkeys*sizeof(struct timer_list), GFP_KERNEL); + if( !s3c_kbd->timers ) + { + printk("error: s3c_kbd_probe kmalloc() for s3c_kbd timers failure\n"); + goto fail; + } + memset(s3c_kbd->timers, 0, pdata->nkeys*sizeof(struct timer_list)); + + /* malloc input_dev for keyboard */ + input_dev=input_allocate_device(); + if( !input_dev ) + { + printk("error: s3c_kbd_probe input_allocate_device() failure\n"); + goto fail; + } + + /* setup input_dev */ + input_dev->name = pdev->name; + input_dev->dev.parent = &pdev->dev; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + + set_bit(EV_KEY,input_dev->evbit); + set_bit(EV_REP,input_dev->evbit); + + /* Initialize all the keys and interrupt */ + for(i=0; i<pdata->nkeys; i++) + { + set_bit(pdata->keys[i].code, input_dev->keybit); + s3c2410_gpio_cfgpin(pdata->keys[i].gpio, pdata->keys[i].setting); + irq_set_irq_type(pdata->keys[i].nIRQ, IRQ_TYPE_EDGE_BOTH); + + rv = request_irq(pdata->keys[i].nIRQ, s3c_kbd_intterupt, IRQF_DISABLED, pdev->name, pdev); + if( rv ) + { + printk("error: request IRQ[%d] for key<%d> failure\n", pdata->keys[i].nIRQ, i); + rv = -EBUSY; + goto fail; + } + + //printk("s3c_kbd request IRQ[%d] for key<%d> ok\n", pdata->keys[i].nIRQ, i); + + /* Initialize all the keys cancel dithering timer */ + setup_timer(&s3c_kbd->timers[i], cancel_dithering_timer_handler, i); + } + + /* register input device */ + rv = input_register_device(input_dev); + if( rv ) + { + printk("error: s3c_kbd_probe input_register_device error!\n"); + goto fail; + } + + /* set s3c_kbd as private data in pdev */ + s3c_kbd->input_dev = input_dev; + s3c_kbd->pdata = pdata; + platform_set_drvdata(pdev, s3c_kbd); + + printk("s3c_kbd_probe ok\n"); + return 0; + +fail: + while(i--) + { + disable_irq(pdata->keys[i].nIRQ); + free_irq(pdata->keys[i].nIRQ, pdev); + del_timer( &s3c_kbd->timers[i] ); + } + + if(input_dev) + { + input_free_device(input_dev); + } + + if(s3c_kbd && s3c_kbd->timers) + { + kfree(s3c_kbd->timers); + } + + if(s3c_kbd) + { + kfree(s3c_kbd); + } + printk("s3c_kbd_probe failed\n"); + + return -ENODEV; +} + +static int s3c_kbd_remove(struct platform_device *pdev) +{ + int i = 0; + s3c_kbd_t *s3c_kbd = platform_get_drvdata(pdev); + + for(i=0; i<s3c_kbd->pdata->nkeys; i++) + { + del_timer( &s3c_kbd->timers[i] ); + disable_irq(s3c_kbd->pdata->keys[i].nIRQ); + free_irq(s3c_kbd->pdata->keys[i].nIRQ, pdev); + } + + input_unregister_device(s3c_kbd->input_dev); + + kfree(s3c_kbd->timers); + kfree(s3c_kbd); + + printk("s3c_kbd_remove ok\n"); + + return 0; +} + +static struct platform_driver s3c_keyboard_driver = { + .probe = s3c_kbd_probe, + .remove = s3c_kbd_remove, + .driver = { + .name = "s3c_kbd", + .owner = THIS_MODULE, + }, +}; + +static int __init s3c_keyboard_drv_init(void) +{ + int rv; + + rv = platform_device_register(&s3c_keyboard_device); + if(rv) + { + printk("S3C keyboard platform device register failure\n"); + return rv; + } + + rv = platform_driver_register(&s3c_keyboard_driver); + if(rv) + { + printk("s3c keyboard platform driver register failure\n"); + platform_device_unregister(&s3c_keyboard_device); + return rv; + } + + printk("s3c keyboard platform driver register ok\n"); + return 0; +} + +static void __exit s3c_keyboard_drv_exit(void) +{ + printk("s3c keyboard driver exit\n"); + + platform_device_unregister(&s3c_keyboard_device); + platform_driver_unregister(&s3c_keyboard_driver); + + return ; +} + +module_init(s3c_keyboard_drv_init); +module_exit(s3c_keyboard_drv_exit); + +MODULE_DESCRIPTION("FL2440 board keyboard input driver platform_driver"); +MODULE_AUTHOR("Guo Wenxue<guowenxue@gmail.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:FL2440 keyboard driver"); + diff --git a/linux-bsp/driver/platdrv_led.c b/linux-bsp/driver/platdrv_led.c new file mode 100644 index 0000000..02d7bd2 --- /dev/null +++ b/linux-bsp/driver/platdrv_led.c @@ -0,0 +1,297 @@ +/********************************************************************************* + * Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> + * All rights reserved. + * + * Filename: platdrv_led.c + * Description: This is the common LED driver runs on S3C24XX. + * + * Version: 1.0.0(10/27/2011~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "10/27/2011 11:39:10 AM" + * + ********************************************************************************/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/version.h> + +#include "platdev_led.h" + +#define TIMER_TIMEOUT 40 + +#define PLATDRV_MAGIC 0x60 +#define LED_OFF _IO (PLATDRV_MAGIC, 0x18) +#define LED_ON _IO (PLATDRV_MAGIC, 0x19) +#define LED_BLINK _IO (PLATDRV_MAGIC, 0x20) + +static int dev_major = 0; + +struct led_device +{ + struct s3c_led_platform_data *data; + struct cdev cdev; + struct class *dev_class; + struct timer_list blink_timer; +} led_device; + + +void led_timer_handler(unsigned long data) +{ + int i; + struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data; + + for(i=0; i<pdata->nleds; i++) + { + if(ON == pdata->leds[i].status) + { + s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level); + } + else + { + s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); + } + + if(ENABLE == pdata->leds[i].blink ) /* LED should blink */ + { + /* Switch status between 0 and 1 to turn LED ON or off */ + pdata->leds[i].status = pdata->leds[i].status ^ 0x01; + } + + mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT); + } +} + + +static int led_open(struct inode *inode, struct file *file) +{ + struct led_device *pdev ; + struct s3c_led_platform_data *pdata; + + pdev = container_of(inode->i_cdev,struct led_device, cdev); + pdata = pdev->data; + + file->private_data = pdata; + + return 0; +} + + +static int led_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static void print_led_help(void) +{ + printk("Follow is the ioctl() command for LED driver:\n"); + printk("Turn LED on command : %u\n", LED_ON); + printk("Turn LED off command : %u\n", LED_OFF); + printk("Turn LED blink command : %u\n", LED_BLINK); +} + +/* compatible with kernel version >=2.6.38*/ +static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct s3c_led_platform_data *pdata = file->private_data; + + switch (cmd) + { + case LED_OFF: + if(pdata->nleds <= arg) + { + printk("LED%ld doesn't exist\n", arg); + return -ENOTTY; + } + pdata->leds[arg].status = OFF; + pdata->leds[arg].blink = DISABLE; + break; + + case LED_ON: + if(pdata->nleds <= arg) + { + printk("LED%ld doesn't exist\n", arg); + return -ENOTTY; + } + pdata->leds[arg].status = ON; + pdata->leds[arg].blink = DISABLE; + break; + + case LED_BLINK: + if(pdata->nleds <= arg) + { + printk("LED%ld doesn't exist\n", arg); + return -ENOTTY; + } + pdata->leds[arg].blink = ENABLE; + pdata->leds[arg].status = ON; + break; + + default: + printk("LED driver don't support ioctl command=%d\n", cmd); + print_led_help(); + return -EINVAL; + + } + return 0; +} + + +static struct file_operations led_fops = { + .owner = THIS_MODULE, + .open = led_open, + .release = led_release, + .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/ +}; + + +static int s3c_led_probe(struct platform_device *dev) +{ + struct s3c_led_platform_data *pdata = dev->dev.platform_data; + int result = 0; + int i; + dev_t devno; + + /* Initialize the LED status */ + for(i=0; i<pdata->nleds; i++) + { + s3c2410_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT); + if(ON == pdata->leds[i].status) + { + s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level); + } + else + { + s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); + } + } + + /* Alloc the device for driver */ + if (0 != dev_major) + { + devno = MKDEV(dev_major, 0); + result = register_chrdev_region(devno, 1, "led"); + } + else + { + result = alloc_chrdev_region(&devno, 0, 1, "led"); + dev_major = MAJOR(devno); + } + + /* Alloc for device major failure */ + if (result < 0) + { + printk("LED driver can't get major %d\n", dev_major); + return result; + } + + /* Initialize button structure and register cdev*/ + memset(&led_device, 0, sizeof(led_device)); + led_device.data = dev->dev.platform_data; + cdev_init (&(led_device.cdev), &led_fops); + led_device.cdev.owner = THIS_MODULE; + + result = cdev_add (&(led_device.cdev), devno , 1); + if (result) + { + printk (KERN_NOTICE "error %d add led device", result ); + goto ERROR; + } + + led_device.dev_class = class_create(THIS_MODULE, "led"); + if(IS_ERR(led_device.dev_class)) + { + printk("LED driver create class failure\n"); + result = -ENOMEM; + goto ERROR; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) + device_create(led_device.dev_class, NULL, devno, NULL, "led"); +#else + device_create (led_device.dev_class, NULL, devno, "led"); +#endif + + /* Initial the LED blink timer */ + init_timer(&(led_device.blink_timer)); + led_device.blink_timer.function = led_timer_handler; + led_device.blink_timer.data = (unsigned long)pdata; + led_device.blink_timer.expires = jiffies + TIMER_TIMEOUT; + add_timer(&(led_device.blink_timer)); + + printk("S3C led driver version 1.0.0 initiliazed.\n"); + + return 0; + + +ERROR: + printk("S3C led driver version 1.0.0 install failure.\n"); + cdev_del(&(led_device.cdev)); + + unregister_chrdev_region(devno, 1); + return result; + +} + +static int s3c_led_remove(struct platform_device *dev) +{ + dev_t devno = MKDEV(dev_major, 0); + + del_timer(&(led_device.blink_timer)); + + cdev_del(&(led_device.cdev)); + device_destroy(led_device.dev_class, devno); + class_destroy(led_device.dev_class); + + unregister_chrdev_region(devno, 1); + printk("S3C led driver removed\n" ); + + return 0; +} + + +static struct platform_driver s3c_led_driver = { + .probe = s3c_led_probe, + .remove = s3c_led_remove, + .driver = { + .name = "s3c_led", + .owner = THIS_MODULE, + }, +}; + + +static int __init platdrv_led_init(void) +{ + int rv = 0; + + rv = platform_driver_register(&s3c_led_driver); + if(rv) + { + printk(KERN_ERR "%s:%d: Can't register platform driver %d\n", __FUNCTION__,__LINE__, rv); + return rv; + } + printk("Regist S3C LED Platform Driver successfully.\n"); + + return 0; +} + + +static void platdrv_led_exit(void) +{ + printk("%s():%d remove LED platform drvier\n", __FUNCTION__,__LINE__); + platform_driver_unregister(&s3c_led_driver); +} + +module_init(platdrv_led_init); +module_exit(platdrv_led_exit); + +module_param(dev_major, int, S_IRUGO); + +MODULE_AUTHOR("GuoWenxue<guowenxue@gmail.com>"); +MODULE_DESCRIPTION("FL2440 LED driver platform driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s3c_platdrv_led"); + diff --git a/linux-bsp/driver/s3c_led.c b/linux-bsp/driver/s3c_led.c new file mode 100644 index 0000000..6f3b804 --- /dev/null +++ b/linux-bsp/driver/s3c_led.c @@ -0,0 +1,281 @@ +/********************************************************************************* + * Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> + * All rights reserved. + * + * Filename: s3c_led.c + * Description: This file + * + * Version: 1.0.0(07/26/2012~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "07/26/2012 10:03:40 PM" + * + ********************************************************************************/ + +#include <linux/module.h> /* Every Linux kernel module must include this head */ +#include <linux/init.h> /* Every Linux kernel module must include this head */ +#include <linux/kernel.h> /* printk() */ +#include <linux/fs.h> /* struct fops */ +#include <linux/errno.h> /* error codes */ +#include <linux/cdev.h> /* cdev_alloc() */ +#include <asm/io.h> /* ioremap() */ +#include <linux/ioport.h> /* request_mem_region() */ + +#include <asm/ioctl.h> /* Linux kernel space head file for macro _IO() to generate ioctl command */ +#include <linux/printk.h> /* Define log level KERN_DEBUG */ + +#define LED_NUM 4 + +#define DISABLE 0 +#define ENABLE 1 + +#define GPIO_INPUT 0x00 +#define GPIO_OUTPUT 0x01 + + +#define PLATDRV_MAGIC 0x60 +#define LED_OFF _IO (PLATDRV_MAGIC, 0x18) +#define LED_ON _IO (PLATDRV_MAGIC, 0x19) + +#define S3C_GPB_BASE 0x56000010 +#define S3C_GPB_LEN 0x10 /* 0x56000010~0x56000020 */ +#define GPBCON_OFFSET 0 +#define GPBDAT_OFFSET 4 +#define GPBUP_OFFSET 8 + +static void __iomem *gpbbase = NULL; + +#define read_reg32(addr) *(volatile unsigned int *)(addr) +#define write_reg32(addr, val) *(volatile unsigned int *)(addr) = (val) + +int led[LED_NUM] = {5,6,8,10}; /* Four LEDs use GPB5,GPB6,GPB8,GPB10 */ +int dev_count = ARRAY_SIZE(led); + +int dev_major = 0; +int dev_minor = 0; +int debug = DISABLE; + +static struct cdev *led_cdev; + + +static int s3c_hw_init(void) +{ + int i; + unsigned int regval; + + if(!request_mem_region(S3C_GPB_BASE, S3C_GPB_LEN, "s3c2440 led")) + { + printk(KERN_ERR "request_mem_region failure!\n"); + return -EBUSY; + } + + if( !(gpbbase=(unsigned int *)ioremap(S3C_GPB_BASE, S3C_GPB_LEN)) ) + { + release_mem_region(S3C_GPB_BASE, S3C_GPB_LEN); + printk(KERN_ERR "release_mem_region failure!\n"); + return -ENOMEM; + } + + + for(i=0; i<dev_count; i++) + { + /* Set GPBCON register, set correspond GPIO port as input or output mode */ + regval = read_reg32(gpbbase+GPBCON_OFFSET); + regval &= ~(0x3<<(2*led[i])); /* Clear the currespond LED GPIO configure register */ + regval |= GPIO_OUTPUT<<(2*led[i]); /* Set the currespond LED GPIO as output mode */ + write_reg32(gpbbase+GPBCON_OFFSET, regval); + + /* Set GPBUP register, set correspond GPIO port pull up resister as enable or disable */ + regval = read_reg32(gpbbase+GPBUP_OFFSET); + regval |= (0x1<<led[i]); /* Disable pull up resister */ + write_reg32(gpbbase+GPBUP_OFFSET, regval); + + /* Set GPBDAT register, set correspond GPIO port power level as high level or low level */ + regval = read_reg32(gpbbase+GPBDAT_OFFSET); + regval |= (0x1<<led[i]); /* This port set to high level, then turn LED off */ + write_reg32(gpbbase+GPBDAT_OFFSET, regval); + } + + return 0; +} + + +static void turn_led(int which, unsigned int cmd) +{ + unsigned int regval; + + regval = read_reg32(gpbbase+GPBDAT_OFFSET); + + if(LED_ON == cmd) + { + regval &= ~(0x1<<led[which]); /* Turn LED On */ + } + else if(LED_OFF == cmd) + { + regval |= (0x1<<led[which]); /* Turn LED off */ + } + + write_reg32(gpbbase+GPBDAT_OFFSET, regval); +} + +static void s3c_hw_term(void) +{ + int i; + unsigned int regval; + + for(i=0; i<dev_count; i++) + { + regval = read_reg32(gpbbase+GPBDAT_OFFSET); + regval |= (0x1<<led[i]); /* Turn LED off */ + write_reg32(gpbbase+GPBDAT_OFFSET, regval); + } + + release_mem_region(S3C_GPB_BASE, S3C_GPB_LEN); + iounmap(gpbbase); +} + + +static int led_open(struct inode *inode, struct file *file) +{ + int minor = iminor(inode); + + file->private_data = (void *)minor; + + printk(KERN_DEBUG "/dev/led%d opened.\n", minor); + return 0; +} + +static int led_release(struct inode *inode, struct file *file) +{ + printk(KERN_DEBUG "/dev/led%d closed.\n", iminor(inode)); + + return 0; +} + +static void print_help(void) +{ + printk("Follow is the ioctl() commands for led driver:\n"); + printk("Turn LED on command : %u\n", LED_ON); + printk("Turn LED off command : %u\n", LED_OFF); + + return; +} + +static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + int which = (int)file->private_data; + + switch (cmd) + { + case LED_ON: + + turn_led(which, LED_ON); + break; + + case LED_OFF: + turn_led(which, LED_OFF); + break; + + default: + printk(KERN_ERR "LED driver don't support ioctl command=%d\n", cmd); + print_help(); + break; + } + + return 0; +} + + +static struct file_operations led_fops = +{ + .owner = THIS_MODULE, + .open = led_open, + .release = led_release, + .unlocked_ioctl = led_ioctl, +}; + +static int __init s3c_led_init(void) +{ + int result; + dev_t devno; + + if( 0 != s3c_hw_init() ) + { + printk(KERN_ERR "s3c2440 LED hardware initialize failure.\n"); + return -ENODEV; + } + + /* Alloc the device for driver */ + if (0 != dev_major) /* Static */ + { + devno = MKDEV(dev_major, 0); + result = register_chrdev_region (devno, dev_count, "led"); + } + else + { + result = alloc_chrdev_region(&devno, dev_minor, dev_count, "led"); + dev_major = MAJOR(devno); + } + + /* Alloc for device major failure */ + if (result < 0) + { + printk(KERN_ERR "S3C led driver can't use major %d\n", dev_major); + return -ENODEV; + } + printk(KERN_DEBUG "S3C led driver use major %d\n", dev_major); + + if(NULL == (led_cdev=cdev_alloc()) ) + { + printk(KERN_ERR "S3C led driver can't alloc for the cdev.\n"); + unregister_chrdev_region(devno, dev_count); + return -ENOMEM; + } + + led_cdev->owner = THIS_MODULE; + cdev_init(led_cdev, &led_fops); + + result = cdev_add(led_cdev, devno, dev_count); + if (0 != result) + { + printk(KERN_INFO "S3C led driver can't reigster cdev: result=%d\n", result); + goto ERROR; + } + + + printk(KERN_ERR "S3C led driver[major=%d] version 1.0.0 installed successfully!\n", dev_major); + return 0; + + +ERROR: + printk(KERN_ERR "S3C led driver installed failure.\n"); + cdev_del(led_cdev); + unregister_chrdev_region(devno, dev_count); + return result; +} + +static void __exit s3c_led_exit(void) +{ + dev_t devno = MKDEV(dev_major, dev_minor); + + s3c_hw_term(); + + cdev_del(led_cdev); + unregister_chrdev_region(devno, dev_count); + + printk(KERN_ERR "S3C led driver version 1.0.0 removed!\n"); + + return ; +} + + +/* These two functions defined in <linux/init.h> */ +module_init(s3c_led_init); +module_exit(s3c_led_exit); + +module_param(debug, int, S_IRUGO); +module_param(dev_major, int, S_IRUGO); + +MODULE_AUTHOR("guowenxue@LingYun IoT Studio"); +MODULE_DESCRIPTION("FL2440 LED linux lowlevel API driver"); +MODULE_LICENSE("GPL"); + diff --git a/linux-bsp/driver/test/makefile b/linux-bsp/driver/test/makefile new file mode 100644 index 0000000..e4a9c8f --- /dev/null +++ b/linux-bsp/driver/test/makefile @@ -0,0 +1,46 @@ +#********************************************************************************* +# Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> +# All rights reserved. +# +# Filename: Makefile +# Description: This Makefile used to compile all the C source code file in current +# folder to respective excutable binary files. +# +# Version: 1.0.0(10/08/2011~) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "11/11/2011 01:29:33 PM" +# +#********************************************************************************/ + +PWD=$(shell pwd) +INSTPATH=/tftp + +CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- +export CC=${CROSS_COMPILE}gcc + +CFLAGS+=-I`dirname ${PWD}` + +SRCFILES = $(wildcard *.c) +BINARIES=$(SRCFILES:%.c=%) + +all: binaries install + +binaries: ${BINARIES} + @echo " Compile over" + +%: %.c + $(CC) -o $@ $< $(CFLAGS) + +install: + cp $(BINARIES) ${INSTPATH} + +clean: + @rm -f version.h + @rm -f *.o $(BINARIES) + @rm -rf *.gdb *.a *.so *.elf* + +distclean: clean + @rm -f tags cscope* + +.PHONY: clean + diff --git a/linux-bsp/driver/test/test_plat_key.c b/linux-bsp/driver/test/test_plat_key.c new file mode 100644 index 0000000..0b60311 --- /dev/null +++ b/linux-bsp/driver/test/test_plat_key.c @@ -0,0 +1,279 @@ +/********************************************************************************* + * Copyright: (C) 2012 Guo Wenxue<Email:guowenxue@gmail.com QQ:281143292> + * All rights reserved. + * + * Filename: event_button.c + * Description: This file used to test GPIO button driver builtin Linux kernel on ARM board + * + * Version: 1.0.0(07/13/2012~) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "07/13/2012 02:46:18 PM" + * + ********************************************************************************/ + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <libgen.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <linux/input.h> +#include <linux/kd.h> +#include <linux/keyboard.h> + +#if 0 /* Just for comment here, Reference to linux-3.3/include/linux/input.h */ +struct input_event +{ + struct timeval time; + __u16 type; /* 0x00:EV_SYN 0x01:EV_KEY 0x04:EV_MSC 0x11:EV_LED*/ + __u16 code; /* key value, which key */ + __s32 value; /* 1: Pressed 0:Not pressed 2:Always Pressed */ +}; +#endif + +#define TRUE 1 +#define FALSE 0 + +#define EV_RELEASED 0 +#define EV_PRESSED 1 +#define EV_REPEAT 2 + +#define BUTTON_CNT 5 + +#define MODE_POLL 0x01 +#define MODE_NORMAL 0x02 + +void usage(char *name); +void display_button_event(struct input_event *ev, int cnt); + +int main(int argc, char **argv) +{ + char *kbd_dev = NULL; + char kbd_name[256] = "Unknown"; + int kbd_fd = -1; + + int rv, opt; + int mode = MODE_NORMAL; + int size = sizeof (struct input_event); + + struct input_event ev[BUTTON_CNT]; + + struct option long_options[] = { + {"device", required_argument, NULL, 'd'}, + {"poll", no_argument, NULL, 'p'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + while ((opt = getopt_long(argc, argv, "d:ph", long_options, NULL)) != -1) + { + switch (opt) + { + case 'd': + kbd_dev = optarg; + break; + + case 'p': + mode = MODE_POLL; + break; + + case 'h': + usage(argv[0]); + return 0; + + default: + break; + } + } + + if(NULL == kbd_dev) + { + usage(argv[0]); + return -1; + } + + if ((getuid ()) != 0) + printf ("You are not root! This may not work...\n"); + + + if ((kbd_fd = open(kbd_dev, O_RDONLY)) < 0) + { + printf("Open %s failure: %s", kbd_dev, strerror(errno)); + return -1; + } + + ioctl (kbd_fd, EVIOCGNAME (sizeof (kbd_name)), kbd_name); + printf ("Monitor input device %s (%s) event with %s mode:\n", kbd_dev, kbd_name, MODE_POLL==mode?"poll":"infilit loop"); + + +#if 0 /* Not implement in the Linux GPIO button driver */ + unsigned char key_b[BUTTON_CNT/8 + 1]; + memset(key_b, 0, sizeof(key_b)); + if(ioctl(kbd_fd, EVIOCGKEY(sizeof(key_b)), key_b) < 0) + { + printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno)); + return -1; + } +#endif + +#if 0 /* Not implement in the Linux GPIO button driver */ + /* rep[0]表示在按键重复出现之前 delay的时间,rep[1]表示按键重复出现的时间间隔。 */ + int rep[2] ={2500, 1000} ; + if(ioctl(kbd_fd, EVIOCSREP, rep) < 0) + { + printf("EVIOCSREP ioctl get error: %s\n", strerror(errno)); + return -1; + } + + if(ioctl(kbd_fd, EVIOCGREP, rep) < 0) + { + printf("EVIOCGKEY ioctl get error: %s\n", strerror(errno)); + return -1; + } + else + { + printf("repeate speed: [0]= %d, [1] = %d/n", rep[0], rep[1]); + } +#endif + + while (1) + { + if(MODE_POLL==mode) + { + fd_set rds; + FD_ZERO(&rds); + FD_SET(kbd_fd, &rds); + + rv = select(kbd_fd + 1, &rds, NULL, NULL, NULL); + if (rv < 0) + { + printf("Select() system call failure: %s\n", strerror(errno)); + goto CleanUp; + } + else if (FD_ISSET(kbd_fd, &rds)) + { + if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size) + { + printf("Reading data from kbd_fd failure: %s\n", strerror(errno)); + break; + } + else + { + display_button_event(ev, rv/size); + } + } + } + else + { + if ((rv = read (kbd_fd, ev, size*BUTTON_CNT )) < size) + { + printf("Reading data from kbd_fd failure: %s\n", strerror(errno)); + break; + } + else + { + display_button_event(ev, rv/size); + } + } + } + +CleanUp: + close(kbd_fd); + + return 0; +} + +void usage(char *name) +{ + char *progname = NULL; + char *ptr = NULL; + + ptr = strdup(name); + progname = basename(ptr); + + printf("Usage: %s [-p] -d <device>\n", progname); + printf(" -d[device ] button device name\n"); + printf(" -p[poll ] Use poll mode, or default use infinit loop.\n"); + printf(" -h[help ] Display this help information\n"); + + free(ptr); + + return; +} + +void display_button_event(struct input_event *ev, int cnt) +{ + int i; + struct timeval pressed_time, duration_time; + + for(i=0; i<cnt; i++) + { + //printf("type:%d code:%d value:%d\n", ev[i].type, ev[i].code, ev[i].value); + if(EV_KEY==ev[i].type && EV_PRESSED==ev[i].value) + { + if(BTN_1 == ev[i].code) + { + pressed_time = ev[i].time; + printf("S1 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec); + } + else if(BTN_2 == ev[i].code) + { + pressed_time = ev[i].time; + printf("S2 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec); + } + else if(BTN_3 == ev[i].code) + { + pressed_time = ev[i].time; + printf("S3 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec); + } + else if(BTN_4 == ev[i].code) + { + pressed_time = ev[i].time; + printf("S4 button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec); + } + else + { + pressed_time = ev[i].time; + printf("button key[%d] pressed time: %ld.%ld\n", ev[i].code, pressed_time.tv_sec, pressed_time.tv_usec); + } + } + if(EV_KEY==ev[i].type && EV_RELEASED==ev[i].value) + { + if(BTN_1 == ev[i].code) + { + timersub(&ev[i].time, &pressed_time, &duration_time); + printf("S1 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec); + printf("S1 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec); + } + else if(BTN_2 == ev[i].code) + { + timersub(&ev[i].time, &pressed_time, &duration_time); + printf("S2 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec); + printf("S2 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec); + } + else if(BTN_3 == ev[i].code) + { + timersub(&ev[i].time, &pressed_time, &duration_time); + printf("S3 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec); + printf("S3 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec); + } + else if(BTN_4 == ev[i].code) + { + timersub(&ev[i].time, &pressed_time, &duration_time); + printf("S4 button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec); + printf("S4 button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec); + } + else + { + timersub(&ev[i].time, &pressed_time, &duration_time); + printf("button key[%d] released time: %ld.%ld\n", ev[i].code, ev[i].time.tv_sec, ev[i].time.tv_usec); + printf("button key[%d] duration time: %ld.%ld\n", ev[i].code, duration_time.tv_sec, duration_time.tv_usec); + } + } + } /* for(i=0; i<cnt; i++) */ +} diff --git a/linux-bsp/driver/test/test_plat_led.c b/linux-bsp/driver/test/test_plat_led.c new file mode 100644 index 0000000..dd2261f --- /dev/null +++ b/linux-bsp/driver/test/test_plat_led.c @@ -0,0 +1,72 @@ +/********************************************************************************* + * Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> + * All rights reserved. + * + * Filename: test_plat_led.c + * Description: This file used to test platdrv_led.c driver + * + * Version: 1.0.0(03/15/2014) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "03/15/2014 02:03:22 PM" + * + ********************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <sys/select.h> +#include <errno.h> + +#define LED_CNT 4 + +#define PLATDRV_MAGIC 0x60 +#define LED_OFF _IO (PLATDRV_MAGIC, 0x18) +#define LED_ON _IO (PLATDRV_MAGIC, 0x19) +#define LED_BLINK _IO (PLATDRV_MAGIC, 0x20) + +static inline msleep(unsigned long ms) +{ + struct timeval tv; + + tv.tv_sec = ms/1000; + tv.tv_usec = (ms%1000)*1000; + + select(0, NULL, NULL, NULL, &tv); +} + +int main (int argc, char **argv) +{ + int i; + int fd; + + if( (fd=open("/dev/led", O_RDWR, 0755)) < 0 ) + { + printf("open led device failure: %s\n", strerror(errno)); + return 0; + } + + for(i=0; i<LED_CNT; i++) + ioctl(fd, LED_BLINK, i); + + sleep(3); + + while(1) + { + for(i=0; i<LED_CNT; i++) + { + ioctl(fd, LED_OFF, i); + msleep(800); + ioctl(fd, LED_ON, i); + msleep(800); + } + } + + close(fd); + + return 0; +} /* ----- End of main() ----- */ + diff --git a/linux-bsp/driver/test/test_s3c_led.c b/linux-bsp/driver/test/test_s3c_led.c new file mode 100644 index 0000000..35290be --- /dev/null +++ b/linux-bsp/driver/test/test_s3c_led.c @@ -0,0 +1,81 @@ +/********************************************************************************* + * Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> + * All rights reserved. + * + * Filename: test_s3c_led.c + * Description: This file is used to tst s3c_led.c driver + * + * Version: 1.0.0(03/15/2014) + * Author: Guo Wenxue <guowenxue@gmail.com> + * ChangeLog: 1, Release initial version on "03/15/2014 02:03:22 PM" + * + ********************************************************************************/ +#include <stdio.h> +#include <stdarg.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <sys/select.h> + +#define LED_CNT 4 +#define DEVNAME_LEN 10 + +#define PLATDRV_MAGIC 0x60 +#define LED_OFF _IO (PLATDRV_MAGIC, 0x18) +#define LED_ON _IO (PLATDRV_MAGIC, 0x19) + +static inline msleep(unsigned long ms) +{ + struct timeval tv; + + tv.tv_sec = ms/1000; + tv.tv_usec = (ms%1000)*1000; + + select(0, NULL, NULL, NULL, &tv); +} + +int main (int argc, char **argv) +{ + int i; + int fd[LED_CNT]; + char dev_name[DEVNAME_LEN]={0,0,0,0}; + + for(i=0; i<LED_CNT; i++) + { + snprintf(dev_name, sizeof(dev_name), "/dev/led%d", i); + fd[i] = open(dev_name, O_RDWR, 0755); + if(fd[i] < 0) + goto err; + } + + while(1) + { + for(i=0; i<LED_CNT; i++) + { + ioctl(fd[i], LED_ON); + msleep(300); + ioctl(fd[i], LED_OFF); + msleep(300); + } + } + + for(i=0; i<LED_CNT; i++) + { + close(fd[i]); + } + + return 0; + +err: + for(i=0; i<LED_CNT; i++) + { + if(fd[i] >= 0) + { + close(fd[i]); + } + } + return -1; +} /* ----- End of main() ----- */ + diff --git a/linux-bsp/driver/x86/Makefile b/linux-bsp/driver/x86/Makefile new file mode 100644 index 0000000..441a6de --- /dev/null +++ b/linux-bsp/driver/x86/Makefile @@ -0,0 +1,29 @@ +#********************************************************************************* +# Copyright: (C) 2017 LingYun IoT Studio <www.iot-yun.com> +# All rights reserved. +# +# Filename: Makefile +# Description: This Makefile used to compile the driver for X86 +# +# Version: 1.0.0(10/08/2011~) +# Author: Guo Wenxue <guowenxue@gmail.com> +# ChangeLog: 1, Release initial version on "11/11/2011 01:29:33 PM" +# +#********************************************************************************/ + +KERNAL_DIR ?= /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +obj-m := kernel_hello.o + +all: + $(MAKE) -C $(KERNAL_DIR) M=$(PWD) modules + @make clear + +clear: + @rm -f *.o *.cmd *.mod.c + @rm -rf *~ core .depend .tmp_versions Module.symvers modules.order -f + @rm -f .*ko.cmd .*.o.cmd .*.o.d .*.cmd *.unsigned + +clean: + @rm -f *.ko diff --git a/linux-bsp/driver/x86/kernel_hello.c b/linux-bsp/driver/x86/kernel_hello.c new file mode 120000 index 0000000..d169853 --- /dev/null +++ b/linux-bsp/driver/x86/kernel_hello.c @@ -0,0 +1 @@ +../kernel_hello.c \ No newline at end of file diff --git a/linux-bsp/patches/gen_patch.sh b/linux-bsp/patches/gen_patch.sh new file mode 100755 index 0000000..55c6efa --- /dev/null +++ b/linux-bsp/patches/gen_patch.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# Description: This shell script used to generate patch file +# Author: guowenxue <guowenxue@gmail.com> +# Version: 1.0.0 + +PROJ_PATH=`pwd` + +PACK_PATH=${PROJ_PATH}/tarballs +PATCH_PATH=${PROJ_PATH}/patches + +BOARD=fl2440 +PATCH_SUFFIX=${BOARD}.patch + +function do_clean() +{ + if [ -f .config ] ; then + set -x + cp .config .cfg-${BOARD} + set +x + fi + + #echo "WARNNING: Maybe need input sudo passwd here: " + bash build.sh clean +} + +if [ $# != 1 ] ; then + echo "Usage: $0 [src_path]" + printf "\nExample: \n" + echo "$0 linux-3.0" + + exit ; +fi + + +SRC=`basename $1` + +if [ ! -d ${SRC} ] ; then + printf "\nERROR: ${SRC} source code not exist, exit now\n\n" + exit +fi + +if [ ! -f ${PACK_PATH}/${SRC}.tar.bz2 ] ; then + printf "\nERROR: ${SRC}.tar.bz2 packet not exist, exit now\n\n" + exit +fi + +cd ${PROJ_PATH} + +cd ${SRC} +do_clean +cd - + +# rename new source code +mv ${SRC} ${SRC}-${BOARD} + +# decompress orignal soruce code packet +tar -xjf ${PACK_PATH}/${SRC}.tar.bz2 + +# generate patch file +if [[ $SRC =~ linux ]] ; then + diff -Nuar -x ".gitignore" ${SRC} ${SRC}-${BOARD} > ${SRC}-${PATCH_SUFFIX} +else + diff -Nuar ${SRC} ${SRC}-${BOARD} > ${SRC}-${PATCH_SUFFIX} +fi + +# remove orignal soruce code +rm -rf ${SRC} + +# recover new source code +mv ${SRC}-${BOARD} ${SRC} + diff --git a/linux-bsp/patches/linux-3.0-fl2440.patch b/linux-bsp/patches/linux-3.0-fl2440.patch new file mode 100644 index 0000000..7721faa --- /dev/null +++ b/linux-bsp/patches/linux-3.0-fl2440.patch @@ -0,0 +1,4153 @@ +diff -Nuar -x .gitignore linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c linux-3.0-fl2440/arch/arm/mach-s3c2440/mach-smdk2440.c +--- linux-3.0/arch/arm/mach-s3c2440/mach-smdk2440.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/arch/arm/mach-s3c2440/mach-smdk2440.c 2020-01-09 16:54:31.213380202 +0800 +@@ -23,6 +23,14 @@ + #include <linux/platform_device.h> + #include <linux/io.h> + ++/* add by guowenxue for norflash */ ++#include <linux/gpio_keys.h> ++#include <linux/input.h> ++#include <linux/mtd/physmap.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/partitions.h> ++#include <linux/mmc/host.h> ++ + #include <asm/mach/arch.h> + #include <asm/mach/map.h> + #include <asm/mach/irq.h> +@@ -44,6 +52,13 @@ + #include <plat/clock.h> + #include <plat/devs.h> + #include <plat/cpu.h> ++#include <plat/mci.h> /* Add by guowenxue to support MMC detect, 2017.5.4 */ ++#include <plat/udc.h> /* Add by guowenxue to support USB device gadget, 2017.5.4 */ ++#include <plat/ts.h> /* Add by guowenxue to support Touch screen, 2011.09.06*/ ++#include <mach/regs-clock.h> /* Add by guowenxue 2012.07.15, for usb_s3c2440_init() */ ++#include <linux/i2c.h> /* Add by guowenxue 2012.10.22, for AT24C02 driver */ ++#include <linux/i2c/at24.h> /* Add by guowenxue 2012.10.22, for AT24C02 driver */ ++#include <linux/delay.h> + + #include <plat/common-smdk.h> + +@@ -102,6 +117,26 @@ + } + }; + ++/* USB device UDC support add by guowenxue 2017.5.4 */ ++static struct s3c2410_udc_mach_info smdk2440_udc_cfg __initdata = { ++ .pullup_pin = S3C2410_GPG(9), ++}; ++ ++/* MMC/SD support add by guowenxue 2017.5.4 */ ++static struct s3c24xx_mci_pdata smdk2440_mmc_cfg __initdata = { ++ .gpio_detect = S3C2410_GPG(10), ++ .gpio_wprotect = S3C2410_GPH(8), ++ .set_power = NULL, ++ .ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34, ++}; ++ ++/*Touch Screen driver info add by guowenxue 2011.09.04 */ ++static struct s3c2410_ts_mach_info smdk2440_ts_cfg __initdata = { ++ .delay = 10000, ++ .presc = 49, ++ .oversampling_shift = 2, ++}; ++ + /* LCD driver info */ + + static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = { +@@ -114,19 +149,34 @@ + + .type = S3C2410_LCDCON1_TFT, + +- .width = 240, +- .height = 320, ++ .width = 320, ++ .height = 240, + +- .pixclock = 166667, /* HCLK 60 MHz, divisor 10 */ +- .xres = 240, +- .yres = 320, +- .bpp = 16, +- .left_margin = 20, +- .right_margin = 8, +- .hsync_len = 4, +- .upper_margin = 8, +- .lower_margin = 7, +- .vsync_len = 4, ++ /*Set value from LCD datasheet, pixclock set refer to ++ *document linux-3.0/Documentation/fb/framebuffer.txt */ ++#if 0 /* For 3.5" TFT-LCD (WXCAT35-TG3#001) */ ++ .pixclock = 156250, /* Dclk-Period =>1000000/Dclk=1000000/6.4*/ ++ .xres = 320, /* Hsync Display Period =>Thd 320*/ ++ .yres = 240, /* Vsync Display Period =>Tvd 240*/ ++ .bpp = 16, /* 16 bpp*/ ++ .left_margin = 38, /* Hsync Front-Porch =>Thf 38*/ ++ .right_margin = 20, /* Hsync Back-Porch =>Thb 20*/ ++ .hsync_len = 30, /* Hsync Pulse Width =>Thp 30*/ ++ .upper_margin = 15, /* Vsync Front-Porch =>Tvf 15*/ ++ .lower_margin = 12, /* Vsync Back-Porch =>Tvb 12*/ ++ .vsync_len = 3, /* Vsync Pulse Width =>Tvp 3*/ ++#else /* For 4.3" TFT-LCD (WXCAT43-TG3#001) */ ++ .pixclock = 111111, /* Dclk-Period =>1000000/Dclk=1000000/9*/ ++ .xres = 480, /* Hsync Display Period =>Thd 480*/ ++ .yres = 272, /* Vsync Display Period =>Tvd 272*/ ++ .bpp = 16, /* 16 bpp*/ ++ .left_margin = 38, /* Hsync Front-Porch =>Thf 38*/ ++ .right_margin = 20, /* Hsync Back-Porch =>Thb 2*/ ++ .hsync_len = 30, /* Hsync Pulse Width =>Thp 41*/ ++ .upper_margin = 15, /* Vsync Front-Porch =>Tvf 2*/ ++ .lower_margin = 12, /* Vsync Back-Porch =>Tvb 2*/ ++ .vsync_len = 3, /* Vsync Pulse Width =>Tvp 10*/ ++#endif + }; + + static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = { +@@ -146,7 +196,113 @@ + .gpdup_mask = 0xffffffff, + #endif + +- .lpcsel = ((0xCE6) & ~7) | 1<<4, ++ .lpcsel = ((0xCE6) & ~7) | 1<<1, ++ ++}; ++ ++ ++/* S3C2440 GPIO buttons add by guowenxue, 2013.05.29 */ ++#ifdef CONFIG_KEYBOARD_GPIO ++static struct gpio_keys_button s3c2440_buttons[] = { ++ { ++ .gpio = S3C2410_GPF(0), /* K1 */ ++ .code = BTN_1, ++ .desc = "Button 1", ++ .active_low = 1, ++ }, ++ { ++ .gpio = S3C2410_GPF(2), /* K2 */ ++ .code = BTN_2, ++ .desc = "Button 2", ++ .active_low = 1, ++ }, ++ { ++ .gpio = S3C2410_GPF(3), /* K3 */ ++ .code = BTN_3, ++ .desc = "Button 3", ++ .active_low = 1, ++ }, ++ { ++ .gpio = S3C2410_GPF(4), /* K4 */ ++ .code = BTN_4, ++ .desc = "Button 4", ++ .active_low = 1, ++ }, ++}; ++ ++static struct gpio_keys_platform_data s3c2440_button_data = { ++ .buttons = s3c2440_buttons, ++ .nbuttons = ARRAY_SIZE(s3c2440_buttons), ++}; ++ ++static struct platform_device s3c2440_button_device = { ++ .name = "gpio-keys", ++ .id = -1, ++ .dev = { ++ .platform_data = &s3c2440_button_data, ++ } ++}; ++#endif ++ ++ ++/* ++ * I2C devices, add by guowenxue ++ */ ++ ++static struct at24_platform_data at24c02 = { ++ .byte_len = SZ_2K / 8, ++ .page_size = 8, ++ .flags = 0, ++}; ++ ++static struct i2c_board_info __initdata smdk2440_i2c_devs[] = { ++ { ++ I2C_BOARD_INFO("24c02", 0x50), ++ .platform_data = &at24c02, ++ }, ++ /* more devices can be added using expansion connectors */ ++}; ++ ++/* Add 4MiB norflash JS28F320 on fl2440 by guowenxue 2012.12.09 */ ++#define NORFLASH_BASE S3C2410_CS1 ++#define NORFLASH_SIZE SZ_4M ++ ++static struct mtd_partition __initdata norflash_partitions[] = { ++ { ++ .name = "norflash bootloader", ++ .offset = 0, ++ .size = SZ_512K, ++ }, ++ { ++ .name = "norflash system", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = MTDPART_SIZ_FULL, ++ }, ++}; ++ ++static struct physmap_flash_data norflash_data = { ++ .width = 2, ++ .parts = norflash_partitions, ++ .nr_parts = ARRAY_SIZE(norflash_partitions), ++}; ++ ++ ++static struct resource norflash_resources[] = { ++ { ++ .start = NORFLASH_BASE, ++ .end = NORFLASH_BASE + NORFLASH_SIZE - 1, ++ .flags = IORESOURCE_MEM, ++ } ++}; ++ ++static struct platform_device s3c_device_norflash = { ++ .name = "physmap-flash", ++ .id = 0, ++ .dev = { ++ .platform_data = &norflash_data, ++ }, ++ .resource = norflash_resources, ++ .num_resources = ARRAY_SIZE(norflash_resources), + }; + + static struct platform_device *smdk2440_devices[] __initdata = { +@@ -155,19 +311,51 @@ + &s3c_device_wdt, + &s3c_device_i2c0, + &s3c_device_iis, ++ &s3c_device_usbgadget, /* Add USB slave gadget by guowenxue, 2017.5.4 */ ++ &s3c_device_norflash, /* Add norflash driver by guowenxue, 2012.12.09 */ ++ &uda1341_codec, /* Add uda1341 driver by guowenxue, 2012.03.30 */ ++ &s3c24xx_uda134x, /* Add uda1341 driver by guowenxue, 2012.03.30 */ ++ &samsung_asoc_dma, /* Add uda1341 driver by guowenxue, 2012.03.30 */ ++ &s3c_device_dm9000, /* Add DM9000 ethernet car driver by guowenxue, 2011.08.30*/ ++ &s3c_device_sdi, /* Add SD card driver by guowenxue, 2011.09.06*/ ++ &s3c_device_rtc, /* Add RTC driver by guowenxue, 2011.09.06*/ ++ &s3c_device_adc, /* Add Touch Screen driver by guowenxue, 2011.09.06*/ ++ &s3c_device_ts, /* Add Touch Screen driver by guowenxue, 2011.09.06*/ ++#ifdef CONFIG_KEYBOARD_GPIO /* Add Button driver by guowenxue, 2013.05.29*/ ++ &s3c2440_button_device ++#endif + }; + ++/* Add by guowenxue 2012.07.15, fix device descriptor read/64, error -62 bug, value refer to datasheet P255 */ ++int usb_s3c2440_init(void) ++{ ++ /* Input Frequency is 12.0000MHz, and MDEV=0x38 PDIV=2 SDIV=2, so output frequency 48.00MHz */ ++ unsigned long upllvalue = (0x38<<12)|(0x02<<4)|(0x02); ++ while (upllvalue != __raw_readl(S3C2410_UPLLCON)) ++ { ++ __raw_writel(upllvalue, S3C2410_UPLLCON); ++ mdelay(1); ++ } ++ ++ return 0; ++} ++ + static void __init smdk2440_map_io(void) + { + s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); +- s3c24xx_init_clocks(16934400); ++ s3c24xx_init_clocks(12000000); /*Modify by guowenxue, 2011.08.30*/ + s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs)); ++ usb_s3c2440_init(); /* Add by guowenxue, 2012.07.15 */ + } + + static void __init smdk2440_machine_init(void) + { ++ s3c24xx_udc_set_platdata(&smdk2440_udc_cfg); /* add USB gadget UDC by guowenxue, 2017.5.4 */ ++ s3c24xx_mci_set_platdata(&smdk2440_mmc_cfg); /* add USB gadget UDC by guowenxue, 2017.5.4 */ + s3c24xx_fb_set_platdata(&smdk2440_fb_info); ++ s3c24xx_ts_set_platdata(&smdk2440_ts_cfg); /*Add Touch Screen info by guowenxue, 2011.09.06*/ + s3c_i2c0_set_platdata(NULL); ++ i2c_register_board_info(0, smdk2440_i2c_devs, ARRAY_SIZE(smdk2440_i2c_devs)); + + platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices)); + smdk_machine_init(); +diff -Nuar -x .gitignore linux-3.0/arch/arm/plat-s3c24xx/common-smdk.c linux-3.0-fl2440/arch/arm/plat-s3c24xx/common-smdk.c +--- linux-3.0/arch/arm/plat-s3c24xx/common-smdk.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/arch/arm/plat-s3c24xx/common-smdk.c 2020-01-09 16:54:31.213380202 +0800 +@@ -48,107 +48,98 @@ + + /* LED devices */ + +-static struct s3c24xx_led_platdata smdk_pdata_led4 = { +- .gpio = S3C2410_GPF(4), ++static struct s3c24xx_led_platdata smdk_pdata_led0 = { ++ .gpio = S3C2410_GPB(5), + .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +- .name = "led4", +- .def_trigger = "timer", ++ .name = "led0", ++ .def_trigger = "heartbeat", + }; + +-static struct s3c24xx_led_platdata smdk_pdata_led5 = { +- .gpio = S3C2410_GPF(5), ++static struct s3c24xx_led_platdata smdk_pdata_led1 = { ++ .gpio = S3C2410_GPB(6), + .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +- .name = "led5", +- .def_trigger = "nand-disk", ++ .name = "led1", ++ //.def_trigger = "nand-disk", + }; + +-static struct s3c24xx_led_platdata smdk_pdata_led6 = { +- .gpio = S3C2410_GPF(6), ++static struct s3c24xx_led_platdata smdk_pdata_led2 = { ++ .gpio = S3C2410_GPB(8), + .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +- .name = "led6", ++ .name = "led2", ++ //.def_trigger = "timer", + }; + +-static struct s3c24xx_led_platdata smdk_pdata_led7 = { +- .gpio = S3C2410_GPF(7), ++static struct s3c24xx_led_platdata smdk_pdata_led3 = { ++ .gpio = S3C2410_GPB(10), + .flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE, +- .name = "led7", ++ .name = "led3", + }; + +-static struct platform_device smdk_led4 = { ++static struct platform_device smdk_led0 = { + .name = "s3c24xx_led", + .id = 0, + .dev = { +- .platform_data = &smdk_pdata_led4, ++ .platform_data = &smdk_pdata_led0, + }, + }; + +-static struct platform_device smdk_led5 = { ++static struct platform_device smdk_led1 = { + .name = "s3c24xx_led", + .id = 1, + .dev = { +- .platform_data = &smdk_pdata_led5, ++ .platform_data = &smdk_pdata_led1, + }, + }; + +-static struct platform_device smdk_led6 = { ++static struct platform_device smdk_led2 = { + .name = "s3c24xx_led", + .id = 2, + .dev = { +- .platform_data = &smdk_pdata_led6, ++ .platform_data = &smdk_pdata_led2, + }, + }; + +-static struct platform_device smdk_led7 = { ++static struct platform_device smdk_led3 = { + .name = "s3c24xx_led", + .id = 3, + .dev = { +- .platform_data = &smdk_pdata_led7, ++ .platform_data = &smdk_pdata_led3, + }, + }; + +-/* NAND parititon from 2.4.18-swl5 */ ++/* NAND parititon from 2.4.18-swl5, modify by guowenxue 2015.11.13, K9F2G08,256MiB */ + + static struct mtd_partition smdk_default_nand_part[] = { +- [0] = { +- .name = "Boot Agent", +- .size = SZ_16K, +- .offset = 0, +- }, +- [1] = { +- .name = "S3C2410 flash partition 1", +- .offset = 0, +- .size = SZ_2M, +- }, +- [2] = { +- .name = "S3C2410 flash partition 2", +- .offset = SZ_4M, +- .size = SZ_4M, +- }, +- [3] = { +- .name = "S3C2410 flash partition 3", +- .offset = SZ_8M, +- .size = SZ_2M, +- }, +- [4] = { +- .name = "S3C2410 flash partition 4", +- .offset = SZ_1M * 10, +- .size = SZ_4M, +- }, +- [5] = { +- .name = "S3C2410 flash partition 5", +- .offset = SZ_1M * 14, +- .size = SZ_1M * 10, +- }, +- [6] = { +- .name = "S3C2410 flash partition 6", +- .offset = SZ_1M * 24, +- .size = SZ_1M * 24, +- }, +- [7] = { +- .name = "S3C2410 flash partition 7", +- .offset = SZ_1M * 48, +- .size = MTDPART_SIZ_FULL, +- } ++ [0] = { ++ .name = "mtdblock0 u-boot 1MB", ++ .offset = 0, ++ .size = SZ_1M*1, /* 0x0000000 ~ 0x0100000 */ ++ }, ++ [1] = { ++ .name = "mtdblock1 kernel 15MB", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_1M*15, /* 0x0100000 ~ 0X1000000 */ ++ }, ++ [2] = { ++ .name = "mtdblock2 rootfs 40MB", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_1M*40, ++ }, ++ [3] = { ++ .name = "mtdblock3 apps 80MB", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_1M*80, ++ }, ++ [4] = { ++ .name = "mtdblock4 data 80MB", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_1M*80, ++ }, ++ [5] = { ++ .name = "mtdblock5 backup 40MB", ++ .offset = MTDPART_OFS_NXTBLK, ++ .size = SZ_1M*40, ++ }, + }; + + static struct s3c2410_nand_set smdk_nand_sets[] = { +@@ -176,10 +167,10 @@ + + static struct platform_device __initdata *smdk_devs[] = { + &s3c_device_nand, +- &smdk_led4, +- &smdk_led5, +- &smdk_led6, +- &smdk_led7, ++ &smdk_led0, ++ &smdk_led1, ++ &smdk_led2, ++ &smdk_led3, + }; + + void __init smdk_machine_init(void) +diff -Nuar -x .gitignore linux-3.0/arch/arm/plat-s3c24xx/devs.c linux-3.0-fl2440/arch/arm/plat-s3c24xx/devs.c +--- linux-3.0/arch/arm/plat-s3c24xx/devs.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/arch/arm/plat-s3c24xx/devs.c 2020-01-09 16:54:31.213380202 +0800 +@@ -299,6 +299,66 @@ + + EXPORT_SYMBOL(s3c_device_iis); + ++#ifdef CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X /* UDA1341 add by guowenxue, 2012.03.30 */ ++#include <sound/s3c24xx_uda134x.h> /* Add by guowenxue, 2012.03.30 */ ++#include <mach/gpio-nrs.h> ++struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data = { ++ .l3_clk = S3C2410_GPB(4), ++ .l3_data = S3C2410_GPB(3), ++ .l3_mode = S3C2410_GPB(2), ++ .model = UDA134X_UDA1341, ++}; ++ ++struct platform_device s3c24xx_uda134x = { ++ .name = "s3c24xx_uda134x", ++ .dev = { ++ .platform_data = &s3c24xx_uda134x_data, ++ } ++}; ++EXPORT_SYMBOL(s3c24xx_uda134x); ++ ++struct platform_device uda1341_codec = { ++ .name = "uda134x-codec", ++ .id = -1, ++}; ++#endif ++ ++#ifdef CONFIG_DM9000 /*DM9000 network device support add by guowenxue 2011.08.30*/ ++#include <linux/dm9000.h> ++static struct resource s3c_dm9000_resource[] = { ++ [0] = { ++ .start = S3C2410_CS4 + 0x300, ++ .end = S3C2410_CS4 + 0x300 + 0x3, ++ .flags = IORESOURCE_MEM ++ }, ++ [1]={ ++ .start = S3C2410_CS4 + 0x300 + 0x4, //CMD pin is A2 ++ .end = S3C2410_CS4 + 0x300 + 0x4 + 0x7c, ++ .flags = IORESOURCE_MEM ++ }, ++ [2] = { ++ .start = IRQ_EINT7, ++ .end = IRQ_EINT7, ++ .flags = IORESOURCE_IRQ ++ }, ++}; ++ ++static struct dm9000_plat_data s3c_device_dm9000_platdata = { ++ .flags= DM9000_PLATF_16BITONLY, ++}; ++ ++struct platform_device s3c_device_dm9000 = { ++ .name= "dm9000", ++ .id= 0, ++ .num_resources= ARRAY_SIZE(s3c_dm9000_resource), ++ .resource= s3c_dm9000_resource, ++ .dev= { ++ .platform_data = &s3c_device_dm9000_platdata, ++ } ++}; ++#endif ++ ++ + /* RTC */ + + static struct resource s3c_rtc_resource[] = { +diff -Nuar -x .gitignore linux-3.0/arch/arm/plat-samsung/include/plat/devs.h linux-3.0-fl2440/arch/arm/plat-samsung/include/plat/devs.h +--- linux-3.0/arch/arm/plat-samsung/include/plat/devs.h 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/arch/arm/plat-samsung/include/plat/devs.h 2020-01-09 16:54:31.273380204 +0800 +@@ -93,6 +93,10 @@ + extern struct platform_device s3c_device_usb_hsudc; + extern struct platform_device s3c_device_usb_hsotg; + ++extern struct platform_device s3c_device_dm9000; /*Add by guowenxue, 2011.08.30*/ ++extern struct platform_device s3c24xx_uda134x; /*Add by guowenxue, 2012.03.30*/ ++extern struct platform_device uda1341_codec; /*Add by guowenxue, 2012.03.30*/ ++ + extern struct platform_device s5pv210_device_ac97; + extern struct platform_device s5pv210_device_pcm0; + extern struct platform_device s5pv210_device_pcm1; +diff -Nuar -x .gitignore linux-3.0/arch/arm/tools/mach-types linux-3.0-fl2440/arch/arm/tools/mach-types +--- linux-3.0/arch/arm/tools/mach-types 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/arch/arm/tools/mach-types 2020-01-09 16:54:31.273380204 +0800 +@@ -85,7 +85,8 @@ + bast ARCH_BAST BAST 331 + h1940 ARCH_H1940 H1940 347 + enp2611 ARCH_ENP2611 ENP2611 356 +-s3c2440 ARCH_S3C2440 S3C2440 362 ++#Changed by guowenxue, 2011.08.30 ++s3c2440 ARCH_S3C2440 S3C2440 1999 + gumstix ARCH_GUMSTIX GUMSTIX 373 + omap_h2 MACH_OMAP_H2 OMAP_H2 382 + e740 MACH_E740 E740 384 +@@ -356,7 +357,8 @@ + snapper_9260 MACH_SNAPPER_9260 SNAPPER_9260 1987 + dsm320 MACH_DSM320 DSM320 1988 + exeda MACH_EXEDA EXEDA 1994 +-mini2440 MACH_MINI2440 MINI2440 1999 ++#Changed by guowenxue, 2011.08.30 ++mini2440 MACH_MINI2440 MINI2440 362 + colibri300 MACH_COLIBRI300 COLIBRI300 2000 + linkstation_ls_hgl MACH_LINKSTATION_LS_HGL LINKSTATION_LS_HGL 2005 + cpuat9g20 MACH_CPUAT9G20 CPUAT9G20 2031 +diff -Nuar -x .gitignore linux-3.0/build.sh linux-3.0-fl2440/build.sh +--- linux-3.0/build.sh 1970-01-01 08:00:00.000000000 +0800 ++++ linux-3.0-fl2440/build.sh 2020-01-09 17:27:02.941417641 +0800 +@@ -0,0 +1,82 @@ ++#!/bin/bash ++ ++BOARD=fl2440 ++TFTP_PATH=/tftp ++IMGS_PATH=../images ++IMG_FILES=linuxrom-${BOARD}.bin ++ ++CROSSTOOL=/opt/xtools/arm920t/bin/arm-linux- ++ ++JOBS=`cat /proc/cpuinfo |grep "processor"|wc -l` ++ ++set -e ++ ++function clean_initramfs() ++{ ++ cd usr ++ rm -f .??* ++ rm -f initramfs_data.o initramfs_data.cpio built-in.o ++ cd - ++} ++ ++function do_clean() ++{ ++ #clean_initramfs ++ rm -f ${IMG_FILES} ++ rm -f cscope* tags ++ make CROSS_COMPILE=${CROSSTOOL} distclean ++} ++ ++function do_build() ++{ ++ clean_initramfs ++ ++ if [ ! -f .config ] ; then ++ cp .cfg-${BOARD} .config ++ fi ++ ++ rm -f arch/arm/boot/dts/*.dtb ++ ++ sed -i "s|^\<ARCH\>.*|ARCH\t\t\t?= arm|g" Makefile ++ sed -i "s|^CROSS_COMPILE.*|CROSS_COMPILE\t?= ${CROSSTOOL}|g" Makefile ++ ++ make -j${JOBS} ++ ++ if [ ! -f ${IMG_FILES} ] ; then ++ mv linuxrom-*.bin ${IMG_FILES} ++ fi ++} ++ ++function do_install() ++{ ++ if [ -d $TFTP_PATH ] ;then ++ echo "cp ${IMG_FILES} $TFTP_PATH" ++ cp ${IMG_FILES} $TFTP_PATH ++ fi ++ ++ if [ -d ${IMGS_PATH} ] ; then ++ echo "cp ${IMG_FILES} $IMGS_PATH" ++ cp ${IMG_FILES} $IMGS_PATH ++ fi ++} ++ ++if [ "y${INITRAMFS}" == "yYES" ] ; then ++ if [ `id -u` != 0 ] ; then ++ printf "\nERROR: kernel build with initramfs support must use root or sudo\n\n" ++ exit; ++ fi ++fi ++ ++ ++if [ "$1" == "clean" ] ; then ++ ++ do_clean ++ exit 0; ++ ++fi ++ ++do_build ++ ++do_install ++ ++ +diff -Nuar -x .gitignore linux-3.0/.cfg-fl2440 linux-3.0-fl2440/.cfg-fl2440 +--- linux-3.0/.cfg-fl2440 1970-01-01 08:00:00.000000000 +0800 ++++ linux-3.0-fl2440/.cfg-fl2440 2020-01-09 17:09:56.601397954 +0800 +@@ -0,0 +1,2407 @@ ++# ++# Automatically generated make config: don't edit ++# Linux/arm 3.0.0 Kernel Configuration ++# ++CONFIG_ARM=y ++CONFIG_HAVE_PWM=y ++CONFIG_SYS_SUPPORTS_APM_EMULATION=y ++CONFIG_GENERIC_GPIO=y ++CONFIG_ARCH_USES_GETTIMEOFFSET=y ++CONFIG_KTIME_SCALAR=y ++CONFIG_HAVE_PROC_CPU=y ++CONFIG_NO_IOPORT=y ++CONFIG_STACKTRACE_SUPPORT=y ++CONFIG_HAVE_LATENCYTOP_SUPPORT=y ++CONFIG_LOCKDEP_SUPPORT=y ++CONFIG_TRACE_IRQFLAGS_SUPPORT=y ++CONFIG_HARDIRQS_SW_RESEND=y ++CONFIG_GENERIC_IRQ_PROBE=y ++CONFIG_RWSEM_GENERIC_SPINLOCK=y ++CONFIG_ARCH_HAS_CPUFREQ=y ++CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y ++CONFIG_GENERIC_HWEIGHT=y ++CONFIG_GENERIC_CALIBRATE_DELAY=y ++CONFIG_NEED_DMA_MAP_STATE=y ++CONFIG_VECTORS_BASE=0xffff0000 ++# CONFIG_ARM_PATCH_PHYS_VIRT is not set ++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" ++CONFIG_HAVE_IRQ_WORK=y ++ ++# ++# General setup ++# ++CONFIG_EXPERIMENTAL=y ++CONFIG_BROKEN_ON_SMP=y ++CONFIG_INIT_ENV_ARG_LIMIT=32 ++CONFIG_CROSS_COMPILE="" ++CONFIG_LOCALVERSION="" ++# CONFIG_LOCALVERSION_AUTO is not set ++CONFIG_HAVE_KERNEL_GZIP=y ++CONFIG_HAVE_KERNEL_LZMA=y ++CONFIG_HAVE_KERNEL_LZO=y ++CONFIG_KERNEL_GZIP=y ++# CONFIG_KERNEL_LZMA is not set ++# CONFIG_KERNEL_LZO is not set ++CONFIG_DEFAULT_HOSTNAME="(none)" ++# CONFIG_SWAP is not set ++CONFIG_SYSVIPC=y ++CONFIG_SYSVIPC_SYSCTL=y ++# CONFIG_POSIX_MQUEUE is not set ++# CONFIG_BSD_PROCESS_ACCT is not set ++# CONFIG_FHANDLE is not set ++# CONFIG_TASKSTATS is not set ++# CONFIG_AUDIT is not set ++CONFIG_HAVE_GENERIC_HARDIRQS=y ++ ++# ++# IRQ subsystem ++# ++CONFIG_GENERIC_HARDIRQS=y ++CONFIG_HAVE_SPARSE_IRQ=y ++CONFIG_GENERIC_IRQ_SHOW=y ++CONFIG_GENERIC_IRQ_CHIP=y ++# CONFIG_SPARSE_IRQ is not set ++ ++# ++# RCU Subsystem ++# ++CONFIG_TINY_RCU=y ++# CONFIG_PREEMPT_RCU is not set ++# CONFIG_RCU_TRACE is not set ++# CONFIG_TREE_RCU_TRACE is not set ++CONFIG_IKCONFIG=y ++CONFIG_IKCONFIG_PROC=y ++CONFIG_LOG_BUF_SHIFT=16 ++# CONFIG_CGROUPS is not set ++# CONFIG_NAMESPACES is not set ++# CONFIG_SCHED_AUTOGROUP is not set ++# CONFIG_SYSFS_DEPRECATED is not set ++# CONFIG_RELAY is not set ++# CONFIG_BLK_DEV_INITRD is not set ++CONFIG_CC_OPTIMIZE_FOR_SIZE=y ++CONFIG_SYSCTL=y ++CONFIG_ANON_INODES=y ++CONFIG_EXPERT=y ++CONFIG_UID16=y ++CONFIG_SYSCTL_SYSCALL=y ++CONFIG_KALLSYMS=y ++CONFIG_HOTPLUG=y ++CONFIG_PRINTK=y ++CONFIG_BUG=y ++CONFIG_ELF_CORE=y ++CONFIG_BASE_FULL=y ++CONFIG_FUTEX=y ++CONFIG_EPOLL=y ++CONFIG_SIGNALFD=y ++CONFIG_TIMERFD=y ++CONFIG_EVENTFD=y ++CONFIG_SHMEM=y ++CONFIG_AIO=y ++CONFIG_EMBEDDED=y ++CONFIG_HAVE_PERF_EVENTS=y ++CONFIG_PERF_USE_VMALLOC=y ++ ++# ++# Kernel Performance Events And Counters ++# ++# CONFIG_PERF_EVENTS is not set ++# CONFIG_PERF_COUNTERS is not set ++CONFIG_VM_EVENT_COUNTERS=y ++CONFIG_COMPAT_BRK=y ++CONFIG_SLAB=y ++# CONFIG_SLUB is not set ++# CONFIG_SLOB is not set ++# CONFIG_PROFILING is not set ++CONFIG_HAVE_OPROFILE=y ++# CONFIG_KPROBES is not set ++CONFIG_HAVE_KPROBES=y ++CONFIG_HAVE_KRETPROBES=y ++CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y ++CONFIG_HAVE_CLK=y ++CONFIG_HAVE_DMA_API_DEBUG=y ++ ++# ++# GCOV-based kernel profiling ++# ++CONFIG_HAVE_GENERIC_DMA_COHERENT=y ++CONFIG_SLABINFO=y ++CONFIG_RT_MUTEXES=y ++CONFIG_BASE_SMALL=0 ++CONFIG_MODULES=y ++CONFIG_MODULE_FORCE_LOAD=y ++CONFIG_MODULE_UNLOAD=y ++# CONFIG_MODULE_FORCE_UNLOAD is not set ++# CONFIG_MODVERSIONS is not set ++# CONFIG_MODULE_SRCVERSION_ALL is not set ++CONFIG_BLOCK=y ++# CONFIG_LBDAF is not set ++# CONFIG_BLK_DEV_BSG is not set ++# CONFIG_BLK_DEV_INTEGRITY is not set ++ ++# ++# IO Schedulers ++# ++CONFIG_IOSCHED_NOOP=y ++CONFIG_IOSCHED_DEADLINE=y ++CONFIG_IOSCHED_CFQ=y ++# CONFIG_DEFAULT_DEADLINE is not set ++CONFIG_DEFAULT_CFQ=y ++# CONFIG_DEFAULT_NOOP is not set ++CONFIG_DEFAULT_IOSCHED="cfq" ++# CONFIG_INLINE_SPIN_TRYLOCK is not set ++# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set ++# CONFIG_INLINE_SPIN_LOCK is not set ++# CONFIG_INLINE_SPIN_LOCK_BH is not set ++# CONFIG_INLINE_SPIN_LOCK_IRQ is not set ++# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set ++CONFIG_INLINE_SPIN_UNLOCK=y ++# CONFIG_INLINE_SPIN_UNLOCK_BH is not set ++CONFIG_INLINE_SPIN_UNLOCK_IRQ=y ++# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set ++# CONFIG_INLINE_READ_TRYLOCK is not set ++# CONFIG_INLINE_READ_LOCK is not set ++# CONFIG_INLINE_READ_LOCK_BH is not set ++# CONFIG_INLINE_READ_LOCK_IRQ is not set ++# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set ++CONFIG_INLINE_READ_UNLOCK=y ++# CONFIG_INLINE_READ_UNLOCK_BH is not set ++CONFIG_INLINE_READ_UNLOCK_IRQ=y ++# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set ++# CONFIG_INLINE_WRITE_TRYLOCK is not set ++# CONFIG_INLINE_WRITE_LOCK is not set ++# CONFIG_INLINE_WRITE_LOCK_BH is not set ++# CONFIG_INLINE_WRITE_LOCK_IRQ is not set ++# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set ++CONFIG_INLINE_WRITE_UNLOCK=y ++# CONFIG_INLINE_WRITE_UNLOCK_BH is not set ++CONFIG_INLINE_WRITE_UNLOCK_IRQ=y ++# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set ++# CONFIG_MUTEX_SPIN_ON_OWNER is not set ++CONFIG_FREEZER=y ++ ++# ++# System Type ++# ++CONFIG_MMU=y ++# CONFIG_ARCH_INTEGRATOR is not set ++# CONFIG_ARCH_REALVIEW is not set ++# CONFIG_ARCH_VERSATILE is not set ++# CONFIG_ARCH_VEXPRESS is not set ++# CONFIG_ARCH_AT91 is not set ++# CONFIG_ARCH_BCMRING is not set ++# CONFIG_ARCH_CLPS711X is not set ++# CONFIG_ARCH_CNS3XXX is not set ++# CONFIG_ARCH_GEMINI is not set ++# CONFIG_ARCH_EBSA110 is not set ++# CONFIG_ARCH_EP93XX is not set ++# CONFIG_ARCH_FOOTBRIDGE is not set ++# CONFIG_ARCH_MXC is not set ++# CONFIG_ARCH_MXS is not set ++# CONFIG_ARCH_NETX is not set ++# CONFIG_ARCH_H720X is not set ++# CONFIG_ARCH_IOP13XX is not set ++# CONFIG_ARCH_IOP32X is not set ++# CONFIG_ARCH_IOP33X is not set ++# CONFIG_ARCH_IXP23XX is not set ++# CONFIG_ARCH_IXP2000 is not set ++# CONFIG_ARCH_IXP4XX is not set ++# CONFIG_ARCH_DOVE is not set ++# CONFIG_ARCH_KIRKWOOD is not set ++# CONFIG_ARCH_LOKI is not set ++# CONFIG_ARCH_LPC32XX is not set ++# CONFIG_ARCH_MV78XX0 is not set ++# CONFIG_ARCH_ORION5X is not set ++# CONFIG_ARCH_MMP is not set ++# CONFIG_ARCH_KS8695 is not set ++# CONFIG_ARCH_W90X900 is not set ++# CONFIG_ARCH_NUC93X is not set ++# CONFIG_ARCH_TEGRA is not set ++# CONFIG_ARCH_PNX4008 is not set ++# CONFIG_ARCH_PXA is not set ++# CONFIG_ARCH_MSM is not set ++# CONFIG_ARCH_SHMOBILE is not set ++# CONFIG_ARCH_RPC is not set ++# CONFIG_ARCH_SA1100 is not set ++CONFIG_ARCH_S3C2410=y ++# CONFIG_ARCH_S3C64XX is not set ++# CONFIG_ARCH_S5P64X0 is not set ++# CONFIG_ARCH_S5PC100 is not set ++# CONFIG_ARCH_S5PV210 is not set ++# CONFIG_ARCH_EXYNOS4 is not set ++# CONFIG_ARCH_SHARK is not set ++# CONFIG_ARCH_TCC_926 is not set ++# CONFIG_ARCH_U300 is not set ++# CONFIG_ARCH_U8500 is not set ++# CONFIG_ARCH_NOMADIK is not set ++# CONFIG_ARCH_DAVINCI is not set ++# CONFIG_ARCH_OMAP is not set ++# CONFIG_PLAT_SPEAR is not set ++# CONFIG_ARCH_VT8500 is not set ++# CONFIG_GPIO_PCA953X is not set ++CONFIG_KEYBOARD_GPIO_POLLED=y ++CONFIG_PLAT_SAMSUNG=y ++ ++# ++# Boot options ++# ++# CONFIG_S3C_BOOT_ERROR_RESET is not set ++CONFIG_S3C_BOOT_UART_FORCE_FIFO=y ++CONFIG_S3C_LOWLEVEL_UART_PORT=0 ++CONFIG_S3C_GPIO_CFG_S3C24XX=y ++CONFIG_S3C_GPIO_PULL_UP=y ++CONFIG_SAMSUNG_GPIO_EXTRA=0 ++CONFIG_S3C_GPIO_SPACE=0 ++CONFIG_S3C_ADC=y ++CONFIG_S3C_DEV_USB_HOST=y ++CONFIG_S3C_DEV_WDT=y ++CONFIG_S3C_DEV_NAND=y ++CONFIG_SAMSUNG_DEV_PWM=y ++CONFIG_S3C24XX_PWM=y ++CONFIG_S3C_DMA=y ++ ++# ++# Power management ++# ++# CONFIG_SAMSUNG_PM_DEBUG is not set ++# CONFIG_SAMSUNG_PM_CHECK is not set ++ ++# ++# Power Domain ++# ++CONFIG_PLAT_S3C24XX=y ++CONFIG_CPU_LLSERIAL_S3C2440_ONLY=y ++CONFIG_CPU_LLSERIAL_S3C2440=y ++CONFIG_S3C2410_CLOCK=y ++CONFIG_S3C24XX_GPIO_EXTRA=0 ++CONFIG_S3C2410_DMA=y ++# CONFIG_S3C2410_DMA_DEBUG is not set ++CONFIG_MACH_SMDK=y ++ ++# ++# System MMU ++# ++ ++# ++# S3C2400 Machines ++# ++CONFIG_S3C2410_PM=y ++CONFIG_S3C2410_GPIO=y ++ ++# ++# S3C2410 Machines ++# ++# CONFIG_ARCH_SMDK2410 is not set ++# CONFIG_ARCH_H1940 is not set ++# CONFIG_MACH_N30 is not set ++# CONFIG_ARCH_BAST is not set ++# CONFIG_MACH_OTOM is not set ++# CONFIG_MACH_AML_M5900 is not set ++# CONFIG_MACH_TCT_HAMMER is not set ++# CONFIG_MACH_VR1000 is not set ++# CONFIG_MACH_QT2410 is not set ++ ++# ++# S3C2412 Machines ++# ++# CONFIG_MACH_JIVE is not set ++# CONFIG_MACH_SMDK2413 is not set ++# CONFIG_MACH_SMDK2412 is not set ++# CONFIG_MACH_VSTMS is not set ++ ++# ++# S3C2416 Machines ++# ++# CONFIG_MACH_SMDK2416 is not set ++CONFIG_CPU_S3C2440=y ++CONFIG_CPU_S3C244X=y ++CONFIG_S3C2440_XTAL_16934400=y ++CONFIG_S3C2440_DMA=y ++ ++# ++# S3C2440 and S3C2442 Machines ++# ++# CONFIG_MACH_ANUBIS is not set ++# CONFIG_MACH_NEO1973_GTA02 is not set ++# CONFIG_MACH_OSIRIS is not set ++# CONFIG_MACH_RX3715 is not set ++CONFIG_ARCH_S3C2440=y ++# CONFIG_MACH_NEXCODER_2440 is not set ++CONFIG_SMDK2440_CPU2440=y ++# CONFIG_SMDK2440_CPU2442 is not set ++# CONFIG_MACH_AT2440EVB is not set ++# CONFIG_MACH_MINI2440 is not set ++# CONFIG_MACH_RX1950 is not set ++ ++# ++# S3C2443 Machines ++# ++# CONFIG_MACH_SMDK2443 is not set ++ ++# ++# Processor Type ++# ++CONFIG_CPU_ARM920T=y ++CONFIG_CPU_32v4T=y ++CONFIG_CPU_ABRT_EV4T=y ++CONFIG_CPU_PABRT_LEGACY=y ++CONFIG_CPU_CACHE_V4WT=y ++CONFIG_CPU_CACHE_VIVT=y ++CONFIG_CPU_COPY_V4WB=y ++CONFIG_CPU_TLB_V4WBI=y ++CONFIG_CPU_CP15=y ++CONFIG_CPU_CP15_MMU=y ++CONFIG_CPU_USE_DOMAINS=y ++ ++# ++# Processor Features ++# ++# CONFIG_ARM_THUMB is not set ++# CONFIG_CPU_ICACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_DISABLE is not set ++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set ++CONFIG_ARM_L1_CACHE_SHIFT=5 ++ ++# ++# Bus support ++# ++# CONFIG_PCI_SYSCALL is not set ++# CONFIG_ARCH_SUPPORTS_MSI is not set ++# CONFIG_PCCARD is not set ++ ++# ++# Kernel Features ++# ++CONFIG_VMSPLIT_3G=y ++# CONFIG_VMSPLIT_2G is not set ++# CONFIG_VMSPLIT_1G is not set ++CONFIG_PAGE_OFFSET=0xC0000000 ++CONFIG_PREEMPT_NONE=y ++# CONFIG_PREEMPT_VOLUNTARY is not set ++# CONFIG_PREEMPT is not set ++CONFIG_HZ=200 ++CONFIG_AEABI=y ++CONFIG_OABI_COMPAT=y ++# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set ++# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set ++CONFIG_HAVE_ARCH_PFN_VALID=y ++# CONFIG_HIGHMEM is not set ++CONFIG_SELECT_MEMORY_MODEL=y ++CONFIG_FLATMEM_MANUAL=y ++CONFIG_FLATMEM=y ++CONFIG_FLAT_NODE_MEM_MAP=y ++CONFIG_HAVE_MEMBLOCK=y ++CONFIG_PAGEFLAGS_EXTENDED=y ++CONFIG_SPLIT_PTLOCK_CPUS=999999 ++# CONFIG_COMPACTION is not set ++# CONFIG_PHYS_ADDR_T_64BIT is not set ++CONFIG_ZONE_DMA_FLAG=0 ++CONFIG_VIRT_TO_BUS=y ++# CONFIG_KSM is not set ++CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 ++CONFIG_NEED_PER_CPU_KM=y ++# CONFIG_CLEANCACHE is not set ++CONFIG_FORCE_MAX_ZONEORDER=11 ++CONFIG_ALIGNMENT_TRAP=y ++# CONFIG_UACCESS_WITH_MEMCPY is not set ++# CONFIG_SECCOMP is not set ++# CONFIG_CC_STACKPROTECTOR is not set ++# CONFIG_DEPRECATED_PARAM_STRUCT is not set ++ ++# ++# Boot options ++# ++# CONFIG_USE_OF is not set ++CONFIG_ZBOOT_ROM_TEXT=0x0 ++CONFIG_ZBOOT_ROM_BSS=0x0 ++CONFIG_CMDLINE="console=ttySAC0,115200 initrd=0x38000000,16M root=/dev/ram0 rw" ++CONFIG_CMDLINE_FROM_BOOTLOADER=y ++# CONFIG_CMDLINE_EXTEND is not set ++# CONFIG_CMDLINE_FORCE is not set ++# CONFIG_XIP_KERNEL is not set ++# CONFIG_KEXEC is not set ++# CONFIG_CRASH_DUMP is not set ++# CONFIG_AUTO_ZRELADDR is not set ++ ++# ++# CPU Power Management ++# ++ ++# ++# CPU Frequency scaling ++# ++# CONFIG_CPU_FREQ is not set ++# CONFIG_CPU_IDLE is not set ++ ++# ++# Floating point emulation ++# ++ ++# ++# At least one emulation must be selected ++# ++CONFIG_FPE_NWFPE=y ++CONFIG_FPE_NWFPE_XP=y ++# CONFIG_FPE_FASTFPE is not set ++ ++# ++# Userspace binary formats ++# ++CONFIG_BINFMT_ELF=y ++# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set ++CONFIG_HAVE_AOUT=y ++# CONFIG_BINFMT_AOUT is not set ++# CONFIG_BINFMT_MISC is not set ++ ++# ++# Power management options ++# ++CONFIG_SUSPEND=y ++CONFIG_SUSPEND_FREEZER=y ++CONFIG_PM_SLEEP=y ++# CONFIG_PM_RUNTIME is not set ++CONFIG_PM=y ++# CONFIG_PM_DEBUG is not set ++# CONFIG_APM_EMULATION is not set ++CONFIG_ARCH_SUSPEND_POSSIBLE=y ++CONFIG_NET=y ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++CONFIG_UNIX=y ++# CONFIG_NET_KEY is not set ++CONFIG_INET=y ++CONFIG_IP_MULTICAST=y ++# CONFIG_IP_ADVANCED_ROUTER is not set ++CONFIG_IP_ROUTE_CLASSID=y ++CONFIG_IP_PNP=y ++CONFIG_IP_PNP_DHCP=y ++CONFIG_IP_PNP_BOOTP=y ++CONFIG_IP_PNP_RARP=y ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE_DEMUX is not set ++CONFIG_IP_MROUTE=y ++# CONFIG_IP_PIMSM_V1 is not set ++# CONFIG_IP_PIMSM_V2 is not set ++# CONFIG_ARPD is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_INET_AH is not set ++# CONFIG_INET_ESP is not set ++# CONFIG_INET_IPCOMP is not set ++# CONFIG_INET_XFRM_TUNNEL is not set ++# CONFIG_INET_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set ++# CONFIG_INET_XFRM_MODE_TUNNEL is not set ++# CONFIG_INET_XFRM_MODE_BEET is not set ++# CONFIG_INET_LRO is not set ++CONFIG_INET_DIAG=y ++CONFIG_INET_TCP_DIAG=y ++# CONFIG_TCP_CONG_ADVANCED is not set ++CONFIG_TCP_CONG_CUBIC=y ++CONFIG_DEFAULT_TCP_CONG="cubic" ++# CONFIG_TCP_MD5SIG is not set ++# CONFIG_IPV6 is not set ++# CONFIG_NETWORK_SECMARK is not set ++# CONFIG_NETWORK_PHY_TIMESTAMPING is not set ++CONFIG_NETFILTER=y ++# CONFIG_NETFILTER_DEBUG is not set ++CONFIG_NETFILTER_ADVANCED=y ++ ++# ++# Core Netfilter Configuration ++# ++CONFIG_NETFILTER_NETLINK=y ++CONFIG_NETFILTER_NETLINK_QUEUE=y ++CONFIG_NETFILTER_NETLINK_LOG=y ++CONFIG_NF_CONNTRACK=y ++CONFIG_NF_CONNTRACK_MARK=y ++CONFIG_NF_CONNTRACK_EVENTS=y ++CONFIG_NF_CONNTRACK_TIMESTAMP=y ++CONFIG_NF_CT_PROTO_DCCP=y ++CONFIG_NF_CT_PROTO_GRE=y ++CONFIG_NF_CT_PROTO_SCTP=y ++CONFIG_NF_CT_PROTO_UDPLITE=y ++CONFIG_NF_CONNTRACK_AMANDA=y ++CONFIG_NF_CONNTRACK_FTP=y ++CONFIG_NF_CONNTRACK_H323=y ++CONFIG_NF_CONNTRACK_IRC=y ++CONFIG_NF_CONNTRACK_BROADCAST=y ++CONFIG_NF_CONNTRACK_NETBIOS_NS=y ++CONFIG_NF_CONNTRACK_SNMP=y ++CONFIG_NF_CONNTRACK_PPTP=y ++CONFIG_NF_CONNTRACK_SANE=y ++CONFIG_NF_CONNTRACK_SIP=y ++CONFIG_NF_CONNTRACK_TFTP=y ++CONFIG_NF_CT_NETLINK=y ++# CONFIG_NETFILTER_TPROXY is not set ++CONFIG_NETFILTER_XTABLES=y ++ ++# ++# Xtables combined modules ++# ++CONFIG_NETFILTER_XT_MARK=y ++CONFIG_NETFILTER_XT_CONNMARK=y ++# CONFIG_NETFILTER_XT_SET is not set ++ ++# ++# Xtables targets ++# ++# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set ++CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y ++CONFIG_NETFILTER_XT_TARGET_CONNMARK=y ++# CONFIG_NETFILTER_XT_TARGET_CT is not set ++# CONFIG_NETFILTER_XT_TARGET_DSCP is not set ++CONFIG_NETFILTER_XT_TARGET_HL=y ++CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y ++# CONFIG_NETFILTER_XT_TARGET_LED is not set ++CONFIG_NETFILTER_XT_TARGET_MARK=y ++CONFIG_NETFILTER_XT_TARGET_NFLOG=y ++CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y ++# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set ++CONFIG_NETFILTER_XT_TARGET_RATEEST=y ++CONFIG_NETFILTER_XT_TARGET_TEE=y ++# CONFIG_NETFILTER_XT_TARGET_TRACE is not set ++CONFIG_NETFILTER_XT_TARGET_TCPMSS=y ++# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set ++ ++# ++# Xtables matches ++# ++CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y ++CONFIG_NETFILTER_XT_MATCH_CLUSTER=y ++CONFIG_NETFILTER_XT_MATCH_COMMENT=y ++CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y ++CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y ++CONFIG_NETFILTER_XT_MATCH_CONNMARK=y ++CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y ++CONFIG_NETFILTER_XT_MATCH_CPU=y ++CONFIG_NETFILTER_XT_MATCH_DCCP=y ++CONFIG_NETFILTER_XT_MATCH_DEVGROUP=y ++CONFIG_NETFILTER_XT_MATCH_DSCP=y ++CONFIG_NETFILTER_XT_MATCH_ESP=y ++CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y ++CONFIG_NETFILTER_XT_MATCH_HELPER=y ++CONFIG_NETFILTER_XT_MATCH_HL=y ++CONFIG_NETFILTER_XT_MATCH_IPRANGE=y ++CONFIG_NETFILTER_XT_MATCH_IPVS=y ++CONFIG_NETFILTER_XT_MATCH_LENGTH=y ++CONFIG_NETFILTER_XT_MATCH_LIMIT=y ++CONFIG_NETFILTER_XT_MATCH_MAC=y ++CONFIG_NETFILTER_XT_MATCH_MARK=y ++CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y ++CONFIG_NETFILTER_XT_MATCH_OSF=y ++CONFIG_NETFILTER_XT_MATCH_OWNER=y ++CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y ++CONFIG_NETFILTER_XT_MATCH_QUOTA=y ++CONFIG_NETFILTER_XT_MATCH_RATEEST=y ++CONFIG_NETFILTER_XT_MATCH_REALM=y ++CONFIG_NETFILTER_XT_MATCH_RECENT=y ++CONFIG_NETFILTER_XT_MATCH_SCTP=y ++CONFIG_NETFILTER_XT_MATCH_STATE=y ++CONFIG_NETFILTER_XT_MATCH_STATISTIC=y ++CONFIG_NETFILTER_XT_MATCH_STRING=y ++CONFIG_NETFILTER_XT_MATCH_TCPMSS=y ++CONFIG_NETFILTER_XT_MATCH_TIME=y ++CONFIG_NETFILTER_XT_MATCH_U32=y ++CONFIG_IP_SET=y ++CONFIG_IP_SET_MAX=256 ++CONFIG_IP_SET_BITMAP_IP=y ++CONFIG_IP_SET_BITMAP_IPMAC=y ++CONFIG_IP_SET_BITMAP_PORT=y ++# CONFIG_IP_SET_HASH_IP is not set ++# CONFIG_IP_SET_HASH_IPPORT is not set ++# CONFIG_IP_SET_HASH_IPPORTIP is not set ++# CONFIG_IP_SET_HASH_IPPORTNET is not set ++# CONFIG_IP_SET_HASH_NET is not set ++# CONFIG_IP_SET_HASH_NETPORT is not set ++CONFIG_IP_SET_LIST_SET=y ++CONFIG_IP_VS=y ++# CONFIG_IP_VS_DEBUG is not set ++CONFIG_IP_VS_TAB_BITS=12 ++ ++# ++# IPVS transport protocol load balancing support ++# ++CONFIG_IP_VS_PROTO_TCP=y ++CONFIG_IP_VS_PROTO_UDP=y ++CONFIG_IP_VS_PROTO_AH_ESP=y ++CONFIG_IP_VS_PROTO_ESP=y ++CONFIG_IP_VS_PROTO_AH=y ++# CONFIG_IP_VS_PROTO_SCTP is not set ++ ++# ++# IPVS scheduler ++# ++CONFIG_IP_VS_RR=y ++CONFIG_IP_VS_WRR=y ++CONFIG_IP_VS_LC=y ++CONFIG_IP_VS_WLC=y ++CONFIG_IP_VS_LBLC=y ++CONFIG_IP_VS_LBLCR=y ++CONFIG_IP_VS_DH=y ++CONFIG_IP_VS_SH=y ++CONFIG_IP_VS_SED=y ++CONFIG_IP_VS_NQ=y ++ ++# ++# IPVS application helper ++# ++# CONFIG_IP_VS_FTP is not set ++CONFIG_IP_VS_NFCT=y ++# CONFIG_IP_VS_PE_SIP is not set ++ ++# ++# IP: Netfilter Configuration ++# ++CONFIG_NF_DEFRAG_IPV4=y ++CONFIG_NF_CONNTRACK_IPV4=y ++CONFIG_NF_CONNTRACK_PROC_COMPAT=y ++CONFIG_IP_NF_QUEUE=y ++CONFIG_IP_NF_IPTABLES=y ++CONFIG_IP_NF_MATCH_AH=y ++CONFIG_IP_NF_MATCH_ECN=y ++CONFIG_IP_NF_MATCH_TTL=y ++CONFIG_IP_NF_FILTER=y ++CONFIG_IP_NF_TARGET_REJECT=y ++CONFIG_IP_NF_TARGET_LOG=y ++CONFIG_IP_NF_TARGET_ULOG=y ++CONFIG_NF_NAT=y ++CONFIG_NF_NAT_NEEDED=y ++CONFIG_IP_NF_TARGET_MASQUERADE=y ++CONFIG_IP_NF_TARGET_NETMAP=y ++CONFIG_IP_NF_TARGET_REDIRECT=y ++CONFIG_NF_NAT_SNMP_BASIC=y ++CONFIG_NF_NAT_PROTO_DCCP=y ++CONFIG_NF_NAT_PROTO_GRE=y ++CONFIG_NF_NAT_PROTO_UDPLITE=y ++CONFIG_NF_NAT_PROTO_SCTP=y ++CONFIG_NF_NAT_FTP=y ++CONFIG_NF_NAT_IRC=y ++CONFIG_NF_NAT_TFTP=y ++CONFIG_NF_NAT_AMANDA=y ++CONFIG_NF_NAT_PPTP=y ++CONFIG_NF_NAT_H323=y ++CONFIG_NF_NAT_SIP=y ++CONFIG_IP_NF_MANGLE=y ++CONFIG_IP_NF_TARGET_CLUSTERIP=y ++CONFIG_IP_NF_TARGET_ECN=y ++CONFIG_IP_NF_TARGET_TTL=y ++CONFIG_IP_NF_RAW=y ++CONFIG_IP_NF_ARPTABLES=y ++CONFIG_IP_NF_ARPFILTER=y ++CONFIG_IP_NF_ARP_MANGLE=y ++# CONFIG_IP_DCCP is not set ++# CONFIG_IP_SCTP is not set ++# CONFIG_RDS is not set ++# CONFIG_TIPC is not set ++# CONFIG_ATM is not set ++# CONFIG_L2TP is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_NET_DSA is not set ++# CONFIG_VLAN_8021Q is not set ++# CONFIG_DECNET is not set ++# CONFIG_LLC2 is not set ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_PHONET is not set ++# CONFIG_IEEE802154 is not set ++# CONFIG_NET_SCHED is not set ++# CONFIG_DCB is not set ++CONFIG_DNS_RESOLVER=y ++# CONFIG_BATMAN_ADV is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++# CONFIG_HAMRADIO is not set ++# CONFIG_CAN is not set ++# CONFIG_IRDA is not set ++CONFIG_BT=y ++CONFIG_BT_L2CAP=y ++CONFIG_BT_SCO=y ++CONFIG_BT_RFCOMM=y ++CONFIG_BT_RFCOMM_TTY=y ++CONFIG_BT_BNEP=y ++CONFIG_BT_BNEP_MC_FILTER=y ++CONFIG_BT_BNEP_PROTO_FILTER=y ++CONFIG_BT_HIDP=y ++ ++# ++# Bluetooth device drivers ++# ++CONFIG_BT_HCIBTUSB=y ++CONFIG_BT_HCIBTSDIO=y ++CONFIG_BT_HCIUART=y ++CONFIG_BT_HCIUART_H4=y ++CONFIG_BT_HCIUART_BCSP=y ++CONFIG_BT_HCIUART_ATH3K=y ++CONFIG_BT_HCIUART_LL=y ++CONFIG_BT_HCIBCM203X=y ++CONFIG_BT_HCIBPA10X=y ++CONFIG_BT_HCIBFUSB=y ++CONFIG_BT_HCIVHCI=y ++CONFIG_BT_MRVL=y ++CONFIG_BT_MRVL_SDIO=y ++CONFIG_BT_ATH3K=y ++# CONFIG_AF_RXRPC is not set ++CONFIG_WIRELESS=y ++CONFIG_WEXT_CORE=y ++CONFIG_WEXT_PROC=y ++CONFIG_CFG80211=y ++# CONFIG_NL80211_TESTMODE is not set ++# CONFIG_CFG80211_DEVELOPER_WARNINGS is not set ++# CONFIG_CFG80211_REG_DEBUG is not set ++CONFIG_CFG80211_DEFAULT_PS=y ++CONFIG_CFG80211_INTERNAL_REGDB=y ++CONFIG_CFG80211_WEXT=y ++CONFIG_WIRELESS_EXT_SYSFS=y ++CONFIG_LIB80211=y ++# CONFIG_LIB80211_DEBUG is not set ++CONFIG_MAC80211=y ++CONFIG_MAC80211_HAS_RC=y ++# CONFIG_MAC80211_RC_PID is not set ++CONFIG_MAC80211_RC_MINSTREL=y ++CONFIG_MAC80211_RC_MINSTREL_HT=y ++CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y ++CONFIG_MAC80211_RC_DEFAULT="minstrel_ht" ++# CONFIG_MAC80211_MESH is not set ++# CONFIG_MAC80211_LEDS is not set ++# CONFIG_MAC80211_DEBUG_MENU is not set ++# CONFIG_WIMAX is not set ++CONFIG_RFKILL=y ++CONFIG_RFKILL_LEDS=y ++CONFIG_RFKILL_INPUT=y ++# CONFIG_RFKILL_GPIO is not set ++# CONFIG_NET_9P is not set ++# CONFIG_CAIF is not set ++# CONFIG_CEPH_LIB is not set ++ ++# ++# Device Drivers ++# ++ ++# ++# Generic Driver Options ++# ++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" ++# CONFIG_DEVTMPFS is not set ++# CONFIG_STANDALONE is not set ++# CONFIG_PREVENT_FIRMWARE_BUILD is not set ++CONFIG_FW_LOADER=y ++CONFIG_FIRMWARE_IN_KERNEL=y ++CONFIG_EXTRA_FIRMWARE="" ++# CONFIG_SYS_HYPERVISOR is not set ++# CONFIG_CONNECTOR is not set ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++# CONFIG_MTD_TESTS is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++CONFIG_MTD_CMDLINE_PARTS=y ++# CONFIG_MTD_AFS_PARTS is not set ++# CONFIG_MTD_AR7_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLKDEVS=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++# CONFIG_INFTL is not set ++# CONFIG_RFD_FTL is not set ++# CONFIG_SSFDC is not set ++# CONFIG_SM_FTL is not set ++# CONFIG_MTD_OOPS is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++CONFIG_MTD_CFI=y ++# CONFIG_MTD_JEDECPROBE is not set ++CONFIG_MTD_GEN_PROBE=y ++# CONFIG_MTD_CFI_ADV_OPTIONS is not set ++CONFIG_MTD_MAP_BANK_WIDTH_1=y ++CONFIG_MTD_MAP_BANK_WIDTH_2=y ++CONFIG_MTD_MAP_BANK_WIDTH_4=y ++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set ++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set ++CONFIG_MTD_CFI_I1=y ++CONFIG_MTD_CFI_I2=y ++# CONFIG_MTD_CFI_I4 is not set ++# CONFIG_MTD_CFI_I8 is not set ++CONFIG_MTD_CFI_INTELEXT=y ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++CONFIG_MTD_CFI_UTIL=y ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_COMPLEX_MAPPINGS is not set ++CONFIG_MTD_PHYSMAP=y ++# CONFIG_MTD_PHYSMAP_COMPAT is not set ++# CONFIG_MTD_ARM_INTEGRATOR is not set ++# CONFIG_MTD_PLATRAM is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_DATAFLASH is not set ++# CONFIG_MTD_M25P80 is not set ++# CONFIG_MTD_SST25L is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_PHRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++CONFIG_MTD_BLOCK2MTD=y ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOC2001PLUS is not set ++CONFIG_MTD_NAND_ECC=y ++# CONFIG_MTD_NAND_ECC_SMC is not set ++CONFIG_MTD_NAND=y ++# CONFIG_MTD_NAND_VERIFY_WRITE is not set ++# CONFIG_MTD_NAND_ECC_BCH is not set ++# CONFIG_MTD_SM_COMMON is not set ++# CONFIG_MTD_NAND_MUSEUM_IDS is not set ++# CONFIG_MTD_NAND_GPIO is not set ++CONFIG_MTD_NAND_IDS=y ++CONFIG_MTD_NAND_S3C2410=y ++# CONFIG_MTD_NAND_S3C2410_DEBUG is not set ++# CONFIG_MTD_NAND_S3C2410_HWECC is not set ++# CONFIG_MTD_NAND_S3C2410_CLKSTOP is not set ++# CONFIG_MTD_NAND_DISKONCHIP is not set ++# CONFIG_MTD_NAND_NANDSIM is not set ++# CONFIG_MTD_NAND_PLATFORM is not set ++# CONFIG_MTD_ALAUDA is not set ++# CONFIG_MTD_ONENAND is not set ++ ++# ++# LPDDR flash memory drivers ++# ++# CONFIG_MTD_LPDDR is not set ++CONFIG_MTD_UBI=y ++CONFIG_MTD_UBI_WL_THRESHOLD=4096 ++CONFIG_MTD_UBI_BEB_RESERVE=1 ++CONFIG_MTD_UBI_GLUEBI=y ++# CONFIG_MTD_UBI_DEBUG is not set ++# CONFIG_PARPORT is not set ++CONFIG_BLK_DEV=y ++# CONFIG_BLK_DEV_COW_COMMON is not set ++CONFIG_BLK_DEV_LOOP=y ++# CONFIG_BLK_DEV_CRYPTOLOOP is not set ++ ++# ++# DRBD disabled because PROC_FS, INET or CONNECTOR not selected ++# ++# CONFIG_BLK_DEV_NBD is not set ++# CONFIG_BLK_DEV_UB is not set ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_COUNT=1 ++CONFIG_BLK_DEV_RAM_SIZE=16384 ++# CONFIG_BLK_DEV_XIP is not set ++# CONFIG_CDROM_PKTCDVD is not set ++# CONFIG_ATA_OVER_ETH is not set ++# CONFIG_MG_DISK is not set ++# CONFIG_BLK_DEV_RBD is not set ++# CONFIG_SENSORS_LIS3LV02D is not set ++CONFIG_MISC_DEVICES=y ++# CONFIG_AD525X_DPOT is not set ++# CONFIG_INTEL_MID_PTI is not set ++# CONFIG_ICS932S401 is not set ++# CONFIG_ENCLOSURE_SERVICES is not set ++# CONFIG_APDS9802ALS is not set ++# CONFIG_ISL29003 is not set ++# CONFIG_ISL29020 is not set ++# CONFIG_SENSORS_TSL2550 is not set ++# CONFIG_SENSORS_BH1780 is not set ++# CONFIG_SENSORS_BH1770 is not set ++# CONFIG_SENSORS_APDS990X is not set ++# CONFIG_HMC6352 is not set ++# CONFIG_DS1682 is not set ++# CONFIG_TI_DAC7512 is not set ++# CONFIG_BMP085 is not set ++# CONFIG_C2PORT is not set ++ ++# ++# EEPROM support ++# ++CONFIG_EEPROM_AT24=y ++# CONFIG_EEPROM_AT25 is not set ++# CONFIG_EEPROM_LEGACY is not set ++# CONFIG_EEPROM_MAX6875 is not set ++# CONFIG_EEPROM_93CX6 is not set ++# CONFIG_IWMC3200TOP is not set ++ ++# ++# Texas Instruments shared transport line discipline ++# ++# CONFIG_TI_ST is not set ++# CONFIG_SENSORS_LIS3_SPI is not set ++# CONFIG_SENSORS_LIS3_I2C is not set ++CONFIG_HAVE_IDE=y ++# CONFIG_IDE is not set ++ ++# ++# SCSI device support ++# ++CONFIG_SCSI_MOD=y ++# CONFIG_RAID_ATTRS is not set ++CONFIG_SCSI=y ++CONFIG_SCSI_DMA=y ++# CONFIG_SCSI_TGT is not set ++# CONFIG_SCSI_NETLINK is not set ++CONFIG_SCSI_PROC_FS=y ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++CONFIG_BLK_DEV_SD=y ++# CONFIG_CHR_DEV_ST is not set ++# CONFIG_CHR_DEV_OSST is not set ++# CONFIG_BLK_DEV_SR is not set ++CONFIG_CHR_DEV_SG=y ++# CONFIG_CHR_DEV_SCH is not set ++CONFIG_SCSI_MULTI_LUN=y ++# CONFIG_SCSI_CONSTANTS is not set ++# CONFIG_SCSI_LOGGING is not set ++CONFIG_SCSI_SCAN_ASYNC=y ++CONFIG_SCSI_WAIT_SCAN=m ++ ++# ++# SCSI Transports ++# ++# CONFIG_SCSI_SPI_ATTRS is not set ++# CONFIG_SCSI_FC_ATTRS is not set ++# CONFIG_SCSI_ISCSI_ATTRS is not set ++# CONFIG_SCSI_SAS_ATTRS is not set ++# CONFIG_SCSI_SAS_LIBSAS is not set ++# CONFIG_SCSI_SRP_ATTRS is not set ++# CONFIG_SCSI_LOWLEVEL is not set ++# CONFIG_SCSI_DH is not set ++# CONFIG_SCSI_OSD_INITIATOR is not set ++# CONFIG_ATA is not set ++# CONFIG_MD is not set ++# CONFIG_TARGET_CORE is not set ++CONFIG_NETDEVICES=y ++# CONFIG_DUMMY is not set ++# CONFIG_BONDING is not set ++# CONFIG_MACVLAN is not set ++# CONFIG_EQUALIZER is not set ++# CONFIG_TUN is not set ++# CONFIG_VETH is not set ++CONFIG_MII=y ++# CONFIG_PHYLIB is not set ++CONFIG_NET_ETHERNET=y ++# CONFIG_AX88796 is not set ++# CONFIG_SMC91X is not set ++CONFIG_DM9000=y ++CONFIG_DM9000_DEBUGLEVEL=4 ++# CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL is not set ++# CONFIG_ENC28J60 is not set ++# CONFIG_ETHOC is not set ++# CONFIG_SMC911X is not set ++# CONFIG_SMSC911X is not set ++# CONFIG_DNET is not set ++# CONFIG_IBM_NEW_EMAC_ZMII is not set ++# CONFIG_IBM_NEW_EMAC_RGMII is not set ++# CONFIG_IBM_NEW_EMAC_TAH is not set ++# CONFIG_IBM_NEW_EMAC_EMAC4 is not set ++# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set ++# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set ++# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set ++# CONFIG_B44 is not set ++# CONFIG_KS8851 is not set ++# CONFIG_KS8851_MLL is not set ++# CONFIG_FTMAC100 is not set ++# CONFIG_NETDEV_1000 is not set ++# CONFIG_NETDEV_10000 is not set ++CONFIG_WLAN=y ++# CONFIG_LIBERTAS_THINFIRM is not set ++# CONFIG_AT76C50X_USB is not set ++# CONFIG_USB_ZD1201 is not set ++# CONFIG_USB_NET_RNDIS_WLAN is not set ++# CONFIG_RTL8187 is not set ++# CONFIG_MAC80211_HWSIM is not set ++# CONFIG_ATH_COMMON is not set ++# CONFIG_B43 is not set ++# CONFIG_B43LEGACY is not set ++# CONFIG_HOSTAP is not set ++# CONFIG_IWM is not set ++# CONFIG_LIBERTAS is not set ++# CONFIG_P54_COMMON is not set ++CONFIG_RT2X00=y ++# CONFIG_RT2500USB is not set ++# CONFIG_RT73USB is not set ++CONFIG_RT2800USB=y ++# CONFIG_RT2800USB_RT33XX is not set ++# CONFIG_RT2800USB_RT35XX is not set ++# CONFIG_RT2800USB_RT53XX is not set ++# CONFIG_RT2800USB_UNKNOWN is not set ++CONFIG_RT2800_LIB=y ++CONFIG_RT2X00_LIB_USB=y ++CONFIG_RT2X00_LIB=y ++CONFIG_RT2X00_LIB_FIRMWARE=y ++CONFIG_RT2X00_LIB_CRYPTO=y ++CONFIG_RT2X00_LIB_LEDS=y ++# CONFIG_RT2X00_DEBUG is not set ++# CONFIG_RTL8192SE is not set ++# CONFIG_RTL8192CU is not set ++# CONFIG_WL1251 is not set ++# CONFIG_WL12XX_MENU is not set ++# CONFIG_ZD1211RW is not set ++# CONFIG_MWIFIEX is not set ++ ++# ++# Enable WiMAX (Networking options) to see the WiMAX drivers ++# ++ ++# ++# USB Network Adapters ++# ++# CONFIG_USB_CATC is not set ++# CONFIG_USB_KAWETH is not set ++# CONFIG_USB_PEGASUS is not set ++# CONFIG_USB_RTL8150 is not set ++# CONFIG_USB_USBNET is not set ++# CONFIG_USB_HSO is not set ++# CONFIG_USB_IPHETH is not set ++# CONFIG_WAN is not set ++ ++# ++# CAIF transport drivers ++# ++CONFIG_PPP=y ++CONFIG_PPP_MULTILINK=y ++CONFIG_PPP_FILTER=y ++CONFIG_PPP_ASYNC=y ++CONFIG_PPP_SYNC_TTY=y ++CONFIG_PPP_DEFLATE=y ++CONFIG_PPP_BSDCOMP=y ++CONFIG_PPP_MPPE=y ++CONFIG_PPPOE=y ++# CONFIG_SLIP is not set ++CONFIG_SLHC=y ++# CONFIG_NETCONSOLE is not set ++# CONFIG_NETPOLL is not set ++# CONFIG_NET_POLL_CONTROLLER is not set ++# CONFIG_ISDN is not set ++# CONFIG_PHONE is not set ++ ++# ++# Input device support ++# ++CONFIG_INPUT=y ++# CONFIG_INPUT_FF_MEMLESS is not set ++CONFIG_INPUT_POLLDEV=y ++# CONFIG_INPUT_SPARSEKMAP is not set ++ ++# ++# Userland interfaces ++# ++CONFIG_INPUT_MOUSEDEV=y ++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set ++CONFIG_INPUT_MOUSEDEV_SCREEN_X=240 ++CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320 ++# CONFIG_INPUT_JOYDEV is not set ++CONFIG_INPUT_EVDEV=y ++# CONFIG_INPUT_EVBUG is not set ++ ++# ++# Input Device Drivers ++# ++CONFIG_INPUT_KEYBOARD=y ++# CONFIG_KEYBOARD_ADP5588 is not set ++# CONFIG_KEYBOARD_ADP5589 is not set ++# CONFIG_KEYBOARD_ATKBD is not set ++# CONFIG_KEYBOARD_QT1070 is not set ++# CONFIG_KEYBOARD_QT2160 is not set ++# CONFIG_KEYBOARD_LKKBD is not set ++CONFIG_KEYBOARD_GPIO=m ++# CONFIG_KEYBOARD_TCA6416 is not set ++# CONFIG_KEYBOARD_MATRIX is not set ++# CONFIG_KEYBOARD_LM8323 is not set ++# CONFIG_KEYBOARD_MAX7359 is not set ++# CONFIG_KEYBOARD_MCS is not set ++# CONFIG_KEYBOARD_MPR121 is not set ++# CONFIG_KEYBOARD_NEWTON is not set ++# CONFIG_KEYBOARD_OPENCORES is not set ++# CONFIG_KEYBOARD_STOWAWAY is not set ++# CONFIG_KEYBOARD_SUNKBD is not set ++# CONFIG_KEYBOARD_XTKBD is not set ++# CONFIG_INPUT_MOUSE is not set ++# CONFIG_INPUT_JOYSTICK is not set ++# CONFIG_INPUT_TABLET is not set ++CONFIG_INPUT_TOUCHSCREEN=y ++# CONFIG_TOUCHSCREEN_ADS7846 is not set ++# CONFIG_TOUCHSCREEN_AD7877 is not set ++# CONFIG_TOUCHSCREEN_AD7879 is not set ++# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set ++# CONFIG_TOUCHSCREEN_BU21013 is not set ++# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set ++# CONFIG_TOUCHSCREEN_DYNAPRO is not set ++# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set ++# CONFIG_TOUCHSCREEN_EETI is not set ++# CONFIG_TOUCHSCREEN_FUJITSU is not set ++CONFIG_TOUCHSCREEN_S3C2410=y ++# CONFIG_TOUCHSCREEN_GUNZE is not set ++# CONFIG_TOUCHSCREEN_ELO is not set ++# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set ++# CONFIG_TOUCHSCREEN_MAX11801 is not set ++# CONFIG_TOUCHSCREEN_MCS5000 is not set ++# CONFIG_TOUCHSCREEN_MTOUCH is not set ++# CONFIG_TOUCHSCREEN_INEXIO is not set ++# CONFIG_TOUCHSCREEN_MK712 is not set ++# CONFIG_TOUCHSCREEN_PENMOUNT is not set ++# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set ++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set ++# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set ++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set ++# CONFIG_TOUCHSCREEN_TSC2005 is not set ++# CONFIG_TOUCHSCREEN_TSC2007 is not set ++# CONFIG_TOUCHSCREEN_W90X900 is not set ++# CONFIG_TOUCHSCREEN_ST1232 is not set ++# CONFIG_TOUCHSCREEN_TPS6507X is not set ++# CONFIG_INPUT_MISC is not set ++ ++# ++# Hardware I/O ports ++# ++# CONFIG_SERIO is not set ++# CONFIG_GAMEPORT is not set ++ ++# ++# Character devices ++# ++CONFIG_VT=y ++CONFIG_CONSOLE_TRANSLATIONS=y ++CONFIG_VT_CONSOLE=y ++CONFIG_HW_CONSOLE=y ++# CONFIG_VT_HW_CONSOLE_BINDING is not set ++CONFIG_UNIX98_PTYS=y ++# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set ++CONFIG_LEGACY_PTYS=y ++CONFIG_LEGACY_PTY_COUNT=5 ++# CONFIG_SERIAL_NONSTANDARD is not set ++# CONFIG_N_GSM is not set ++# CONFIG_TRACE_SINK is not set ++CONFIG_DEVKMEM=y ++ ++# ++# Serial drivers ++# ++# CONFIG_SERIAL_8250 is not set ++ ++# ++# Non-8250 serial port support ++# ++CONFIG_SERIAL_SAMSUNG=y ++CONFIG_SERIAL_SAMSUNG_UARTS=3 ++CONFIG_SERIAL_SAMSUNG_CONSOLE=y ++CONFIG_SERIAL_S3C2440=y ++# CONFIG_SERIAL_MAX3100 is not set ++# CONFIG_SERIAL_MAX3107 is not set ++CONFIG_SERIAL_CORE=y ++CONFIG_SERIAL_CORE_CONSOLE=y ++# CONFIG_SERIAL_TIMBERDALE is not set ++# CONFIG_SERIAL_ALTERA_JTAGUART is not set ++# CONFIG_SERIAL_ALTERA_UART is not set ++# CONFIG_SERIAL_IFX6X60 is not set ++# CONFIG_SERIAL_XILINX_PS_UART is not set ++# CONFIG_TTY_PRINTK is not set ++# CONFIG_HVC_DCC is not set ++# CONFIG_IPMI_HANDLER is not set ++# CONFIG_HW_RANDOM is not set ++# CONFIG_R3964 is not set ++# CONFIG_RAW_DRIVER is not set ++# CONFIG_TCG_TPM is not set ++# CONFIG_RAMOOPS is not set ++CONFIG_I2C=y ++CONFIG_I2C_BOARDINFO=y ++CONFIG_I2C_COMPAT=y ++CONFIG_I2C_CHARDEV=y ++# CONFIG_I2C_MUX is not set ++# CONFIG_I2C_HELPER_AUTO is not set ++CONFIG_I2C_SMBUS=y ++ ++# ++# I2C Algorithms ++# ++CONFIG_I2C_ALGOBIT=y ++# CONFIG_I2C_ALGOPCF is not set ++# CONFIG_I2C_ALGOPCA is not set ++ ++# ++# I2C Hardware Bus support ++# ++ ++# ++# I2C system bus drivers (mostly embedded / system-on-chip) ++# ++# CONFIG_I2C_DESIGNWARE is not set ++# CONFIG_I2C_GPIO is not set ++# CONFIG_I2C_OCORES is not set ++# CONFIG_I2C_PCA_PLATFORM is not set ++# CONFIG_I2C_PXA_PCI is not set ++CONFIG_HAVE_S3C2410_I2C=y ++CONFIG_I2C_S3C2410=y ++# CONFIG_I2C_SIMTEC is not set ++# CONFIG_I2C_XILINX is not set ++ ++# ++# External I2C/SMBus adapter drivers ++# ++# CONFIG_I2C_DIOLAN_U2C is not set ++# CONFIG_I2C_PARPORT_LIGHT is not set ++# CONFIG_I2C_TAOS_EVM is not set ++# CONFIG_I2C_TINY_USB is not set ++ ++# ++# Other I2C/SMBus bus drivers ++# ++# CONFIG_I2C_STUB is not set ++# CONFIG_I2C_DEBUG_CORE is not set ++# CONFIG_I2C_DEBUG_ALGO is not set ++# CONFIG_I2C_DEBUG_BUS is not set ++CONFIG_SPI=y ++CONFIG_SPI_MASTER=y ++ ++# ++# SPI Master Controller Drivers ++# ++# CONFIG_SPI_ALTERA is not set ++CONFIG_SPI_BITBANG=y ++# CONFIG_SPI_GPIO is not set ++# CONFIG_SPI_OC_TINY is not set ++# CONFIG_SPI_PXA2XX_PCI is not set ++CONFIG_SPI_S3C24XX=y ++# CONFIG_SPI_S3C24XX_FIQ is not set ++# CONFIG_SPI_S3C24XX_GPIO is not set ++# CONFIG_SPI_XILINX is not set ++# CONFIG_SPI_DESIGNWARE is not set ++ ++# ++# SPI Protocol Masters ++# ++# CONFIG_SPI_SPIDEV is not set ++# CONFIG_SPI_TLE62X0 is not set ++ ++# ++# PPS support ++# ++# CONFIG_PPS is not set ++ ++# ++# PPS generators support ++# ++ ++# ++# PTP clock support ++# ++ ++# ++# Enable Device Drivers -> PPS to see the PTP clock options. ++# ++CONFIG_ARCH_REQUIRE_GPIOLIB=y ++CONFIG_GPIOLIB=y ++# CONFIG_GPIO_SYSFS is not set ++ ++# ++# Memory mapped GPIO drivers: ++# ++# CONFIG_GPIO_BASIC_MMIO is not set ++# CONFIG_GPIO_IT8761E is not set ++ ++# ++# I2C GPIO expanders: ++# ++# CONFIG_GPIO_MAX7300 is not set ++# CONFIG_GPIO_MAX732X is not set ++# CONFIG_GPIO_PCF857X is not set ++# CONFIG_GPIO_SX150X is not set ++# CONFIG_GPIO_ADP5588 is not set ++ ++# ++# PCI GPIO expanders: ++# ++ ++# ++# SPI GPIO expanders: ++# ++# CONFIG_GPIO_MAX7301 is not set ++# CONFIG_GPIO_MCP23S08 is not set ++# CONFIG_GPIO_MC33880 is not set ++# CONFIG_GPIO_74X164 is not set ++ ++# ++# AC97 GPIO expanders: ++# ++ ++# ++# MODULbus GPIO expanders: ++# ++# CONFIG_W1 is not set ++# CONFIG_POWER_SUPPLY is not set ++# CONFIG_HWMON is not set ++# CONFIG_THERMAL is not set ++# CONFIG_WATCHDOG is not set ++CONFIG_SSB_POSSIBLE=y ++ ++# ++# Sonics Silicon Backplane ++# ++# CONFIG_SSB is not set ++CONFIG_BCMA_POSSIBLE=y ++ ++# ++# Broadcom specific AMBA ++# ++# CONFIG_BCMA is not set ++# CONFIG_MFD_SUPPORT is not set ++# CONFIG_REGULATOR is not set ++CONFIG_MEDIA_SUPPORT=y ++ ++# ++# Multimedia core support ++# ++CONFIG_MEDIA_CONTROLLER=y ++CONFIG_VIDEO_DEV=y ++CONFIG_VIDEO_V4L2_COMMON=y ++CONFIG_VIDEO_V4L2_SUBDEV_API=y ++# CONFIG_DVB_CORE is not set ++CONFIG_VIDEO_MEDIA=y ++ ++# ++# Multimedia drivers ++# ++# CONFIG_RC_CORE is not set ++# CONFIG_MEDIA_ATTACH is not set ++CONFIG_MEDIA_TUNER=y ++# CONFIG_MEDIA_TUNER_CUSTOMISE is not set ++CONFIG_MEDIA_TUNER_SIMPLE=y ++CONFIG_MEDIA_TUNER_TDA8290=y ++CONFIG_MEDIA_TUNER_TDA827X=y ++CONFIG_MEDIA_TUNER_TDA18271=y ++CONFIG_MEDIA_TUNER_TDA9887=y ++CONFIG_MEDIA_TUNER_TEA5761=y ++CONFIG_MEDIA_TUNER_TEA5767=y ++CONFIG_MEDIA_TUNER_MT20XX=y ++CONFIG_MEDIA_TUNER_XC2028=y ++CONFIG_MEDIA_TUNER_XC5000=y ++CONFIG_MEDIA_TUNER_MC44S803=y ++CONFIG_VIDEO_V4L2=y ++CONFIG_VIDEO_CAPTURE_DRIVERS=y ++# CONFIG_VIDEO_ADV_DEBUG is not set ++# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set ++# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set ++ ++# ++# Encoders, decoders, sensors and other helper chips ++# ++ ++# ++# Audio decoders, processors and mixers ++# ++# CONFIG_VIDEO_TVAUDIO is not set ++# CONFIG_VIDEO_TDA7432 is not set ++# CONFIG_VIDEO_TDA9840 is not set ++# CONFIG_VIDEO_TEA6415C is not set ++# CONFIG_VIDEO_TEA6420 is not set ++# CONFIG_VIDEO_MSP3400 is not set ++# CONFIG_VIDEO_CS5345 is not set ++# CONFIG_VIDEO_CS53L32A is not set ++# CONFIG_VIDEO_TLV320AIC23B is not set ++# CONFIG_VIDEO_WM8775 is not set ++# CONFIG_VIDEO_WM8739 is not set ++# CONFIG_VIDEO_VP27SMPX is not set ++ ++# ++# RDS decoders ++# ++# CONFIG_VIDEO_SAA6588 is not set ++ ++# ++# Video decoders ++# ++# CONFIG_VIDEO_ADV7180 is not set ++# CONFIG_VIDEO_BT819 is not set ++# CONFIG_VIDEO_BT856 is not set ++# CONFIG_VIDEO_BT866 is not set ++# CONFIG_VIDEO_KS0127 is not set ++# CONFIG_VIDEO_SAA7110 is not set ++# CONFIG_VIDEO_SAA711X is not set ++# CONFIG_VIDEO_SAA7191 is not set ++# CONFIG_VIDEO_TVP514X is not set ++# CONFIG_VIDEO_TVP5150 is not set ++# CONFIG_VIDEO_TVP7002 is not set ++# CONFIG_VIDEO_VPX3220 is not set ++ ++# ++# Video and audio decoders ++# ++# CONFIG_VIDEO_SAA717X is not set ++# CONFIG_VIDEO_CX25840 is not set ++ ++# ++# MPEG video encoders ++# ++# CONFIG_VIDEO_CX2341X is not set ++ ++# ++# Video encoders ++# ++# CONFIG_VIDEO_SAA7127 is not set ++# CONFIG_VIDEO_SAA7185 is not set ++# CONFIG_VIDEO_ADV7170 is not set ++# CONFIG_VIDEO_ADV7175 is not set ++# CONFIG_VIDEO_ADV7343 is not set ++# CONFIG_VIDEO_AK881X is not set ++ ++# ++# Camera sensor devices ++# ++# CONFIG_VIDEO_OV7670 is not set ++# CONFIG_VIDEO_MT9V011 is not set ++# CONFIG_VIDEO_MT9V032 is not set ++# CONFIG_VIDEO_TCM825X is not set ++ ++# ++# Video improvement chips ++# ++# CONFIG_VIDEO_UPD64031A is not set ++# CONFIG_VIDEO_UPD64083 is not set ++ ++# ++# Miscelaneous helper chips ++# ++# CONFIG_VIDEO_THS7303 is not set ++# CONFIG_VIDEO_M52790 is not set ++# CONFIG_VIDEO_VIVI is not set ++# CONFIG_VIDEO_CPIA2 is not set ++# CONFIG_VIDEO_SR030PC30 is not set ++# CONFIG_VIDEO_NOON010PC30 is not set ++# CONFIG_VIDEO_M5MOLS is not set ++# CONFIG_SOC_CAMERA is not set ++CONFIG_V4L_USB_DRIVERS=y ++CONFIG_USB_VIDEO_CLASS=y ++CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y ++CONFIG_USB_GSPCA=y ++# CONFIG_USB_M5602 is not set ++# CONFIG_USB_STV06XX is not set ++# CONFIG_USB_GL860 is not set ++# CONFIG_USB_GSPCA_BENQ is not set ++# CONFIG_USB_GSPCA_CONEX is not set ++# CONFIG_USB_GSPCA_CPIA1 is not set ++# CONFIG_USB_GSPCA_ETOMS is not set ++# CONFIG_USB_GSPCA_FINEPIX is not set ++# CONFIG_USB_GSPCA_JEILINJ is not set ++# CONFIG_USB_GSPCA_KINECT is not set ++# CONFIG_USB_GSPCA_KONICA is not set ++# CONFIG_USB_GSPCA_MARS is not set ++# CONFIG_USB_GSPCA_MR97310A is not set ++# CONFIG_USB_GSPCA_NW80X is not set ++# CONFIG_USB_GSPCA_OV519 is not set ++# CONFIG_USB_GSPCA_OV534 is not set ++# CONFIG_USB_GSPCA_OV534_9 is not set ++# CONFIG_USB_GSPCA_PAC207 is not set ++# CONFIG_USB_GSPCA_PAC7302 is not set ++# CONFIG_USB_GSPCA_PAC7311 is not set ++# CONFIG_USB_GSPCA_SN9C2028 is not set ++# CONFIG_USB_GSPCA_SN9C20X is not set ++# CONFIG_USB_GSPCA_SONIXB is not set ++# CONFIG_USB_GSPCA_SONIXJ is not set ++# CONFIG_USB_GSPCA_SPCA500 is not set ++# CONFIG_USB_GSPCA_SPCA501 is not set ++# CONFIG_USB_GSPCA_SPCA505 is not set ++# CONFIG_USB_GSPCA_SPCA506 is not set ++# CONFIG_USB_GSPCA_SPCA508 is not set ++# CONFIG_USB_GSPCA_SPCA561 is not set ++# CONFIG_USB_GSPCA_SPCA1528 is not set ++# CONFIG_USB_GSPCA_SQ905 is not set ++# CONFIG_USB_GSPCA_SQ905C is not set ++# CONFIG_USB_GSPCA_SQ930X is not set ++# CONFIG_USB_GSPCA_STK014 is not set ++# CONFIG_USB_GSPCA_STV0680 is not set ++# CONFIG_USB_GSPCA_SUNPLUS is not set ++# CONFIG_USB_GSPCA_T613 is not set ++# CONFIG_USB_GSPCA_TV8532 is not set ++# CONFIG_USB_GSPCA_VC032X is not set ++# CONFIG_USB_GSPCA_VICAM is not set ++# CONFIG_USB_GSPCA_XIRLINK_CIT is not set ++# CONFIG_USB_GSPCA_ZC3XX is not set ++# CONFIG_VIDEO_PVRUSB2 is not set ++# CONFIG_VIDEO_HDPVR is not set ++# CONFIG_VIDEO_USBVISION is not set ++# CONFIG_USB_ET61X251 is not set ++# CONFIG_USB_SN9C102 is not set ++# CONFIG_USB_PWC is not set ++# CONFIG_USB_ZR364XX is not set ++# CONFIG_USB_STKWEBCAM is not set ++# CONFIG_USB_S2255 is not set ++# CONFIG_V4L_MEM2MEM_DRIVERS is not set ++# CONFIG_RADIO_ADAPTERS is not set ++ ++# ++# Graphics support ++# ++# CONFIG_DRM is not set ++# CONFIG_VGASTATE is not set ++# CONFIG_VIDEO_OUTPUT_CONTROL is not set ++CONFIG_FB=y ++CONFIG_FIRMWARE_EDID=y ++# CONFIG_FB_DDC is not set ++# CONFIG_FB_BOOT_VESA_SUPPORT is not set ++CONFIG_FB_CFB_FILLRECT=y ++CONFIG_FB_CFB_COPYAREA=y ++CONFIG_FB_CFB_IMAGEBLIT=y ++# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set ++# CONFIG_FB_SYS_FILLRECT is not set ++# CONFIG_FB_SYS_COPYAREA is not set ++# CONFIG_FB_SYS_IMAGEBLIT is not set ++# CONFIG_FB_FOREIGN_ENDIAN is not set ++# CONFIG_FB_SYS_FOPS is not set ++# CONFIG_FB_WMT_GE_ROPS is not set ++# CONFIG_FB_SVGALIB is not set ++# CONFIG_FB_MACMODES is not set ++# CONFIG_FB_BACKLIGHT is not set ++CONFIG_FB_MODE_HELPERS=y ++# CONFIG_FB_TILEBLITTING is not set ++ ++# ++# Frame buffer hardware drivers ++# ++# CONFIG_FB_S1D13XXX is not set ++CONFIG_FB_S3C2410=y ++CONFIG_FB_S3C2410_DEBUG=y ++# CONFIG_FB_UDL is not set ++# CONFIG_FB_VIRTUAL is not set ++# CONFIG_FB_METRONOME is not set ++# CONFIG_FB_BROADSHEET is not set ++# CONFIG_BACKLIGHT_LCD_SUPPORT is not set ++ ++# ++# Display device support ++# ++# CONFIG_DISPLAY_SUPPORT is not set ++ ++# ++# Console display driver support ++# ++CONFIG_DUMMY_CONSOLE=y ++CONFIG_FRAMEBUFFER_CONSOLE=y ++# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set ++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set ++# CONFIG_FONTS is not set ++CONFIG_FONT_8x8=y ++CONFIG_FONT_8x16=y ++CONFIG_LOGO=y ++# CONFIG_LOGO_LINUX_MONO is not set ++# CONFIG_LOGO_LINUX_VGA16 is not set ++CONFIG_LOGO_LINUX_CLUT224=y ++CONFIG_SOUND=y ++CONFIG_SOUND_OSS_CORE=y ++# CONFIG_SOUND_OSS_CORE_PRECLAIM is not set ++CONFIG_SND=y ++CONFIG_SND_TIMER=y ++CONFIG_SND_PCM=y ++CONFIG_SND_JACK=y ++# CONFIG_SND_SEQUENCER is not set ++CONFIG_SND_OSSEMUL=y ++CONFIG_SND_MIXER_OSS=y ++CONFIG_SND_PCM_OSS=y ++CONFIG_SND_PCM_OSS_PLUGINS=y ++CONFIG_SND_DYNAMIC_MINORS=y ++CONFIG_SND_SUPPORT_OLD_API=y ++CONFIG_SND_VERBOSE_PROCFS=y ++CONFIG_SND_VERBOSE_PRINTK=y ++# CONFIG_SND_DEBUG is not set ++# CONFIG_SND_RAWMIDI_SEQ is not set ++# CONFIG_SND_OPL3_LIB_SEQ is not set ++# CONFIG_SND_OPL4_LIB_SEQ is not set ++# CONFIG_SND_SBAWE_SEQ is not set ++# CONFIG_SND_EMU10K1_SEQ is not set ++# CONFIG_SND_DRIVERS is not set ++# CONFIG_SND_ARM is not set ++# CONFIG_SND_SPI is not set ++# CONFIG_SND_USB is not set ++CONFIG_SND_SOC=y ++# CONFIG_SND_SOC_CACHE_LZO is not set ++CONFIG_SND_SOC_SAMSUNG=y ++CONFIG_SND_S3C24XX_I2S=y ++# CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650 is not set ++CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X=y ++# CONFIG_SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 is not set ++# CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES is not set ++CONFIG_SND_SOC_I2C_AND_SPI=y ++# CONFIG_SND_SOC_ALL_CODECS is not set ++CONFIG_SND_SOC_L3=y ++CONFIG_SND_SOC_UDA134X=y ++# CONFIG_SOUND_PRIME is not set ++CONFIG_HID_SUPPORT=y ++CONFIG_HID=y ++# CONFIG_HIDRAW is not set ++ ++# ++# USB Input Devices ++# ++CONFIG_USB_HID=y ++# CONFIG_HID_PID is not set ++# CONFIG_USB_HIDDEV is not set ++ ++# ++# Special HID drivers ++# ++# CONFIG_HID_A4TECH is not set ++# CONFIG_HID_ACRUX is not set ++# CONFIG_HID_APPLE is not set ++# CONFIG_HID_BELKIN is not set ++# CONFIG_HID_CHERRY is not set ++# CONFIG_HID_CHICONY is not set ++# CONFIG_HID_PRODIKEYS is not set ++# CONFIG_HID_CYPRESS is not set ++# CONFIG_HID_DRAGONRISE is not set ++# CONFIG_HID_EMS_FF is not set ++# CONFIG_HID_ELECOM is not set ++# CONFIG_HID_EZKEY is not set ++# CONFIG_HID_KEYTOUCH is not set ++# CONFIG_HID_KYE is not set ++# CONFIG_HID_UCLOGIC is not set ++# CONFIG_HID_WALTOP is not set ++# CONFIG_HID_GYRATION is not set ++# CONFIG_HID_TWINHAN is not set ++# CONFIG_HID_KENSINGTON is not set ++# CONFIG_HID_LCPOWER is not set ++# CONFIG_HID_LOGITECH is not set ++# CONFIG_HID_MAGICMOUSE is not set ++# CONFIG_HID_MICROSOFT is not set ++# CONFIG_HID_MONTEREY is not set ++# CONFIG_HID_MULTITOUCH is not set ++# CONFIG_HID_NTRIG is not set ++# CONFIG_HID_ORTEK is not set ++# CONFIG_HID_PANTHERLORD is not set ++# CONFIG_HID_PETALYNX is not set ++# CONFIG_HID_PICOLCD is not set ++# CONFIG_HID_QUANTA is not set ++# CONFIG_HID_ROCCAT is not set ++# CONFIG_HID_ROCCAT_ARVO is not set ++# CONFIG_HID_ROCCAT_KONE is not set ++# CONFIG_HID_ROCCAT_KONEPLUS is not set ++# CONFIG_HID_ROCCAT_KOVAPLUS is not set ++# CONFIG_HID_ROCCAT_PYRA is not set ++# CONFIG_HID_SAMSUNG is not set ++# CONFIG_HID_SONY is not set ++# CONFIG_HID_SUNPLUS is not set ++# CONFIG_HID_GREENASIA is not set ++# CONFIG_HID_SMARTJOYPLUS is not set ++# CONFIG_HID_TOPSEED is not set ++# CONFIG_HID_THRUSTMASTER is not set ++# CONFIG_HID_WACOM is not set ++# CONFIG_HID_ZEROPLUS is not set ++# CONFIG_HID_ZYDACRON is not set ++CONFIG_USB_SUPPORT=y ++CONFIG_USB_ARCH_HAS_HCD=y ++CONFIG_USB_ARCH_HAS_OHCI=y ++# CONFIG_USB_ARCH_HAS_EHCI is not set ++CONFIG_USB=y ++# CONFIG_USB_DEBUG is not set ++CONFIG_USB_ANNOUNCE_NEW_DEVICES=y ++ ++# ++# Miscellaneous USB options ++# ++CONFIG_USB_DEVICEFS=y ++CONFIG_USB_DEVICE_CLASS=y ++CONFIG_USB_DYNAMIC_MINORS=y ++# CONFIG_USB_OTG_WHITELIST is not set ++# CONFIG_USB_OTG_BLACKLIST_HUB is not set ++# CONFIG_USB_MON is not set ++# CONFIG_USB_WUSB is not set ++# CONFIG_USB_WUSB_CBAF is not set ++ ++# ++# USB Host Controller Drivers ++# ++# CONFIG_USB_C67X00_HCD is not set ++# CONFIG_USB_OXU210HP_HCD is not set ++# CONFIG_USB_ISP116X_HCD is not set ++# CONFIG_USB_ISP1760_HCD is not set ++# CONFIG_USB_ISP1362_HCD is not set ++CONFIG_USB_OHCI_HCD=y ++# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set ++# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set ++CONFIG_USB_OHCI_LITTLE_ENDIAN=y ++# CONFIG_USB_SL811_HCD is not set ++# CONFIG_USB_R8A66597_HCD is not set ++# CONFIG_USB_HWA_HCD is not set ++# CONFIG_USB_MUSB_HDRC is not set ++ ++# ++# USB Device Class drivers ++# ++# CONFIG_USB_ACM is not set ++# CONFIG_USB_PRINTER is not set ++# CONFIG_USB_WDM is not set ++# CONFIG_USB_TMC is not set ++ ++# ++# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may ++# ++ ++# ++# also be needed; see USB_STORAGE Help for more info ++# ++CONFIG_USB_STORAGE=y ++# CONFIG_USB_STORAGE_DEBUG is not set ++# CONFIG_USB_STORAGE_REALTEK is not set ++# CONFIG_USB_STORAGE_DATAFAB is not set ++# CONFIG_USB_STORAGE_FREECOM is not set ++# CONFIG_USB_STORAGE_ISD200 is not set ++# CONFIG_USB_STORAGE_USBAT is not set ++# CONFIG_USB_STORAGE_SDDR09 is not set ++# CONFIG_USB_STORAGE_SDDR55 is not set ++# CONFIG_USB_STORAGE_JUMPSHOT is not set ++# CONFIG_USB_STORAGE_ALAUDA is not set ++# CONFIG_USB_STORAGE_ONETOUCH is not set ++# CONFIG_USB_STORAGE_KARMA is not set ++# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set ++# CONFIG_USB_STORAGE_ENE_UB6250 is not set ++# CONFIG_USB_UAS is not set ++# CONFIG_USB_LIBUSUAL is not set ++ ++# ++# USB Imaging devices ++# ++# CONFIG_USB_MDC800 is not set ++# CONFIG_USB_MICROTEK is not set ++ ++# ++# USB port drivers ++# ++CONFIG_USB_SERIAL=y ++# CONFIG_USB_SERIAL_CONSOLE is not set ++# CONFIG_USB_EZUSB is not set ++# CONFIG_USB_SERIAL_GENERIC is not set ++# CONFIG_USB_SERIAL_AIRCABLE is not set ++# CONFIG_USB_SERIAL_ARK3116 is not set ++# CONFIG_USB_SERIAL_BELKIN is not set ++CONFIG_USB_SERIAL_CH341=y ++# CONFIG_USB_SERIAL_WHITEHEAT is not set ++# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set ++# CONFIG_USB_SERIAL_CP210X is not set ++# CONFIG_USB_SERIAL_CYPRESS_M8 is not set ++# CONFIG_USB_SERIAL_EMPEG is not set ++CONFIG_USB_SERIAL_FTDI_SIO=y ++# CONFIG_USB_SERIAL_FUNSOFT is not set ++# CONFIG_USB_SERIAL_VISOR is not set ++# CONFIG_USB_SERIAL_IPAQ is not set ++# CONFIG_USB_SERIAL_IR is not set ++# CONFIG_USB_SERIAL_EDGEPORT is not set ++# CONFIG_USB_SERIAL_EDGEPORT_TI is not set ++# CONFIG_USB_SERIAL_GARMIN is not set ++# CONFIG_USB_SERIAL_IPW is not set ++# CONFIG_USB_SERIAL_IUU is not set ++# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set ++# CONFIG_USB_SERIAL_KEYSPAN is not set ++# CONFIG_USB_SERIAL_KLSI is not set ++# CONFIG_USB_SERIAL_KOBIL_SCT is not set ++# CONFIG_USB_SERIAL_MCT_U232 is not set ++# CONFIG_USB_SERIAL_MOS7720 is not set ++# CONFIG_USB_SERIAL_MOS7840 is not set ++# CONFIG_USB_SERIAL_MOTOROLA is not set ++# CONFIG_USB_SERIAL_NAVMAN is not set ++CONFIG_USB_SERIAL_PL2303=y ++# CONFIG_USB_SERIAL_OTI6858 is not set ++# CONFIG_USB_SERIAL_QCAUX is not set ++# CONFIG_USB_SERIAL_QUALCOMM is not set ++# CONFIG_USB_SERIAL_SPCP8X5 is not set ++# CONFIG_USB_SERIAL_HP4X is not set ++# CONFIG_USB_SERIAL_SAFE is not set ++# CONFIG_USB_SERIAL_SIEMENS_MPI is not set ++# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set ++# CONFIG_USB_SERIAL_SYMBOL is not set ++# CONFIG_USB_SERIAL_TI is not set ++# CONFIG_USB_SERIAL_CYBERJACK is not set ++# CONFIG_USB_SERIAL_XIRCOM is not set ++CONFIG_USB_SERIAL_WWAN=y ++CONFIG_USB_SERIAL_OPTION=y ++# CONFIG_USB_SERIAL_OMNINET is not set ++# CONFIG_USB_SERIAL_OPTICON is not set ++# CONFIG_USB_SERIAL_VIVOPAY_SERIAL is not set ++# CONFIG_USB_SERIAL_ZIO is not set ++# CONFIG_USB_SERIAL_SSU100 is not set ++# CONFIG_USB_SERIAL_DEBUG is not set ++ ++# ++# USB Miscellaneous drivers ++# ++# CONFIG_USB_EMI62 is not set ++# CONFIG_USB_EMI26 is not set ++# CONFIG_USB_ADUTUX is not set ++# CONFIG_USB_SEVSEG is not set ++# CONFIG_USB_RIO500 is not set ++# CONFIG_USB_LEGOTOWER is not set ++# CONFIG_USB_LCD is not set ++# CONFIG_USB_LED is not set ++# CONFIG_USB_CYPRESS_CY7C63 is not set ++# CONFIG_USB_CYTHERM is not set ++# CONFIG_USB_IDMOUSE is not set ++# CONFIG_USB_FTDI_ELAN is not set ++# CONFIG_USB_APPLEDISPLAY is not set ++# CONFIG_USB_LD is not set ++# CONFIG_USB_TRANCEVIBRATOR is not set ++# CONFIG_USB_IOWARRIOR is not set ++# CONFIG_USB_TEST is not set ++# CONFIG_USB_ISIGHTFW is not set ++# CONFIG_USB_YUREX is not set ++CONFIG_USB_GADGET=y ++CONFIG_USB_GADGET_DEBUG_FILES=y ++CONFIG_USB_GADGET_VBUS_DRAW=2 ++CONFIG_USB_GADGET_SELECTED=y ++# CONFIG_USB_GADGET_FUSB300 is not set ++# CONFIG_USB_GADGET_R8A66597 is not set ++CONFIG_USB_GADGET_S3C2410=y ++CONFIG_USB_S3C2410=y ++# CONFIG_USB_S3C2410_DEBUG is not set ++# CONFIG_USB_GADGET_S3C_HSUDC is not set ++# CONFIG_USB_GADGET_PXA_U2O is not set ++# CONFIG_USB_GADGET_M66592 is not set ++# CONFIG_USB_GADGET_DUMMY_HCD is not set ++# CONFIG_USB_ZERO is not set ++# CONFIG_USB_AUDIO is not set ++# CONFIG_USB_ETH is not set ++# CONFIG_USB_G_NCM is not set ++# CONFIG_USB_GADGETFS is not set ++# CONFIG_USB_FUNCTIONFS is not set ++CONFIG_USB_FILE_STORAGE=m ++# CONFIG_USB_FILE_STORAGE_TEST is not set ++CONFIG_USB_MASS_STORAGE=m ++CONFIG_USB_G_SERIAL=m ++# CONFIG_USB_MIDI_GADGET is not set ++# CONFIG_USB_G_PRINTER is not set ++# CONFIG_USB_CDC_COMPOSITE is not set ++# CONFIG_USB_G_MULTI is not set ++# CONFIG_USB_G_HID is not set ++# CONFIG_USB_G_DBGP is not set ++# CONFIG_USB_G_WEBCAM is not set ++ ++# ++# OTG and related infrastructure ++# ++# CONFIG_USB_GPIO_VBUS is not set ++# CONFIG_USB_ULPI is not set ++# CONFIG_NOP_USB_XCEIV is not set ++CONFIG_MMC=y ++# CONFIG_MMC_DEBUG is not set ++# CONFIG_MMC_UNSAFE_RESUME is not set ++# CONFIG_MMC_CLKGATE is not set ++ ++# ++# MMC/SD/SDIO Card Drivers ++# ++CONFIG_MMC_BLOCK=y ++CONFIG_MMC_BLOCK_MINORS=8 ++CONFIG_MMC_BLOCK_BOUNCE=y ++# CONFIG_SDIO_UART is not set ++# CONFIG_MMC_TEST is not set ++ ++# ++# MMC/SD/SDIO Host Controller Drivers ++# ++# CONFIG_MMC_SDHCI is not set ++CONFIG_MMC_SPI=y ++CONFIG_MMC_S3C=y ++# CONFIG_MMC_S3C_HW_SDIO_IRQ is not set ++CONFIG_MMC_S3C_PIO=y ++# CONFIG_MMC_S3C_DMA is not set ++# CONFIG_MMC_S3C_PIODMA is not set ++# CONFIG_MMC_DW is not set ++# CONFIG_MMC_VUB300 is not set ++# CONFIG_MMC_USHC is not set ++# CONFIG_MEMSTICK is not set ++CONFIG_NEW_LEDS=y ++CONFIG_LEDS_CLASS=y ++ ++# ++# LED drivers ++# ++# CONFIG_LEDS_LM3530 is not set ++CONFIG_LEDS_S3C24XX=m ++# CONFIG_LEDS_PCA9532 is not set ++# CONFIG_LEDS_GPIO is not set ++# CONFIG_LEDS_LP3944 is not set ++# CONFIG_LEDS_LP5521 is not set ++# CONFIG_LEDS_LP5523 is not set ++# CONFIG_LEDS_PCA955X is not set ++# CONFIG_LEDS_DAC124S085 is not set ++# CONFIG_LEDS_PWM is not set ++# CONFIG_LEDS_BD2802 is not set ++# CONFIG_LEDS_LT3593 is not set ++CONFIG_LEDS_TRIGGERS=y ++ ++# ++# LED Triggers ++# ++CONFIG_LEDS_TRIGGER_TIMER=y ++CONFIG_LEDS_TRIGGER_HEARTBEAT=y ++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set ++# CONFIG_LEDS_TRIGGER_GPIO is not set ++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set ++ ++# ++# iptables trigger is under Netfilter config (LED target) ++# ++# CONFIG_NFC_DEVICES is not set ++# CONFIG_ACCESSIBILITY is not set ++CONFIG_RTC_LIB=y ++CONFIG_RTC_CLASS=y ++CONFIG_RTC_HCTOSYS=y ++CONFIG_RTC_HCTOSYS_DEVICE="rtc0" ++# CONFIG_RTC_DEBUG is not set ++ ++# ++# RTC interfaces ++# ++CONFIG_RTC_INTF_SYSFS=y ++CONFIG_RTC_INTF_PROC=y ++CONFIG_RTC_INTF_DEV=y ++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set ++# CONFIG_RTC_DRV_TEST is not set ++ ++# ++# I2C RTC drivers ++# ++CONFIG_RTC_DRV_DS1307=y ++# CONFIG_RTC_DRV_DS1374 is not set ++# CONFIG_RTC_DRV_DS1672 is not set ++# CONFIG_RTC_DRV_DS3232 is not set ++# CONFIG_RTC_DRV_MAX6900 is not set ++# CONFIG_RTC_DRV_RS5C372 is not set ++# CONFIG_RTC_DRV_ISL1208 is not set ++# CONFIG_RTC_DRV_ISL12022 is not set ++# CONFIG_RTC_DRV_X1205 is not set ++# CONFIG_RTC_DRV_PCF8563 is not set ++# CONFIG_RTC_DRV_PCF8583 is not set ++# CONFIG_RTC_DRV_M41T80 is not set ++# CONFIG_RTC_DRV_BQ32K is not set ++# CONFIG_RTC_DRV_S35390A is not set ++# CONFIG_RTC_DRV_FM3130 is not set ++# CONFIG_RTC_DRV_RX8581 is not set ++# CONFIG_RTC_DRV_RX8025 is not set ++# CONFIG_RTC_DRV_EM3027 is not set ++# CONFIG_RTC_DRV_RV3029C2 is not set ++ ++# ++# SPI RTC drivers ++# ++# CONFIG_RTC_DRV_M41T93 is not set ++# CONFIG_RTC_DRV_M41T94 is not set ++# CONFIG_RTC_DRV_DS1305 is not set ++# CONFIG_RTC_DRV_DS1390 is not set ++# CONFIG_RTC_DRV_MAX6902 is not set ++# CONFIG_RTC_DRV_R9701 is not set ++# CONFIG_RTC_DRV_RS5C348 is not set ++# CONFIG_RTC_DRV_DS3234 is not set ++# CONFIG_RTC_DRV_PCF2123 is not set ++ ++# ++# Platform RTC drivers ++# ++# CONFIG_RTC_DRV_CMOS is not set ++# CONFIG_RTC_DRV_DS1286 is not set ++# CONFIG_RTC_DRV_DS1511 is not set ++# CONFIG_RTC_DRV_DS1553 is not set ++# CONFIG_RTC_DRV_DS1742 is not set ++# CONFIG_RTC_DRV_STK17TA8 is not set ++# CONFIG_RTC_DRV_M48T86 is not set ++# CONFIG_RTC_DRV_M48T35 is not set ++# CONFIG_RTC_DRV_M48T59 is not set ++# CONFIG_RTC_DRV_MSM6242 is not set ++# CONFIG_RTC_DRV_BQ4802 is not set ++# CONFIG_RTC_DRV_RP5C01 is not set ++# CONFIG_RTC_DRV_V3020 is not set ++ ++# ++# on-CPU RTC drivers ++# ++CONFIG_RTC_DRV_S3C=y ++# CONFIG_DMADEVICES is not set ++# CONFIG_AUXDISPLAY is not set ++# CONFIG_UIO is not set ++# CONFIG_STAGING is not set ++ ++# ++# File systems ++# ++CONFIG_EXT2_FS=y ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XIP is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_EXT4_FS is not set ++# CONFIG_REISERFS_FS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_XFS_FS is not set ++# CONFIG_OCFS2_FS is not set ++# CONFIG_BTRFS_FS is not set ++# CONFIG_NILFS2_FS is not set ++CONFIG_FS_POSIX_ACL=y ++CONFIG_FILE_LOCKING=y ++CONFIG_FSNOTIFY=y ++CONFIG_DNOTIFY=y ++CONFIG_INOTIFY_USER=y ++# CONFIG_FANOTIFY is not set ++# CONFIG_QUOTA is not set ++# CONFIG_QUOTACTL is not set ++# CONFIG_AUTOFS4_FS is not set ++# CONFIG_FUSE_FS is not set ++CONFIG_GENERIC_ACL=y ++ ++# ++# Caches ++# ++# CONFIG_FSCACHE is not set ++ ++# ++# CD-ROM/DVD Filesystems ++# ++# CONFIG_ISO9660_FS is not set ++# CONFIG_UDF_FS is not set ++ ++# ++# DOS/FAT/NT Filesystems ++# ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_FAT_DEFAULT_CODEPAGE=437 ++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" ++CONFIG_NTFS_FS=y ++# CONFIG_NTFS_DEBUG is not set ++CONFIG_NTFS_RW=y ++ ++# ++# Pseudo filesystems ++# ++CONFIG_PROC_FS=y ++CONFIG_PROC_SYSCTL=y ++CONFIG_PROC_PAGE_MONITOR=y ++CONFIG_SYSFS=y ++CONFIG_TMPFS=y ++CONFIG_TMPFS_POSIX_ACL=y ++CONFIG_TMPFS_XATTR=y ++# CONFIG_HUGETLB_PAGE is not set ++CONFIG_CONFIGFS_FS=y ++CONFIG_MISC_FILESYSTEMS=y ++# CONFIG_ADFS_FS is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_ECRYPT_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EFS_FS is not set ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++CONFIG_JFFS2_FS_WRITEBUFFER=y ++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set ++CONFIG_JFFS2_SUMMARY=y ++# CONFIG_JFFS2_FS_XATTR is not set ++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set ++CONFIG_JFFS2_ZLIB=y ++# CONFIG_JFFS2_LZO is not set ++CONFIG_JFFS2_RTIME=y ++# CONFIG_JFFS2_RUBIN is not set ++CONFIG_UBIFS_FS=y ++CONFIG_UBIFS_FS_XATTR=y ++CONFIG_UBIFS_FS_ADVANCED_COMPR=y ++CONFIG_UBIFS_FS_LZO=y ++CONFIG_UBIFS_FS_ZLIB=y ++# CONFIG_UBIFS_FS_DEBUG is not set ++# CONFIG_LOGFS is not set ++CONFIG_CRAMFS=y ++# CONFIG_SQUASHFS is not set ++# CONFIG_VXFS_FS is not set ++# CONFIG_MINIX_FS is not set ++# CONFIG_OMFS_FS is not set ++# CONFIG_HPFS_FS is not set ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_ROMFS_FS is not set ++# CONFIG_PSTORE is not set ++# CONFIG_SYSV_FS is not set ++# CONFIG_UFS_FS is not set ++CONFIG_NETWORK_FILESYSTEMS=y ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFS_V3_ACL=y ++CONFIG_NFS_V4=y ++# CONFIG_NFS_V4_1 is not set ++CONFIG_ROOT_NFS=y ++# CONFIG_NFS_USE_LEGACY_DNS is not set ++CONFIG_NFS_USE_KERNEL_DNS=y ++# CONFIG_NFS_USE_NEW_IDMAPPER is not set ++# CONFIG_NFSD is not set ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++CONFIG_NFS_ACL_SUPPORT=y ++CONFIG_NFS_COMMON=y ++CONFIG_SUNRPC=y ++CONFIG_SUNRPC_GSS=y ++# CONFIG_CEPH_FS is not set ++# CONFIG_CIFS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_CODA_FS is not set ++# CONFIG_AFS_FS is not set ++ ++# ++# Partition Types ++# ++CONFIG_PARTITION_ADVANCED=y ++# CONFIG_ACORN_PARTITION is not set ++# CONFIG_OSF_PARTITION is not set ++# CONFIG_AMIGA_PARTITION is not set ++# CONFIG_ATARI_PARTITION is not set ++# CONFIG_MAC_PARTITION is not set ++CONFIG_MSDOS_PARTITION=y ++CONFIG_BSD_DISKLABEL=y ++# CONFIG_MINIX_SUBPARTITION is not set ++CONFIG_SOLARIS_X86_PARTITION=y ++# CONFIG_UNIXWARE_DISKLABEL is not set ++# CONFIG_LDM_PARTITION is not set ++# CONFIG_SGI_PARTITION is not set ++# CONFIG_ULTRIX_PARTITION is not set ++# CONFIG_SUN_PARTITION is not set ++# CONFIG_KARMA_PARTITION is not set ++# CONFIG_EFI_PARTITION is not set ++# CONFIG_SYSV68_PARTITION is not set ++CONFIG_NLS=y ++CONFIG_NLS_DEFAULT="iso8859-1" ++CONFIG_NLS_CODEPAGE_437=y ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++CONFIG_NLS_ASCII=y ++CONFIG_NLS_ISO8859_1=y ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++CONFIG_NLS_UTF8=y ++# CONFIG_DLM is not set ++ ++# ++# Kernel hacking ++# ++# CONFIG_PRINTK_TIME is not set ++CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 ++# CONFIG_ENABLE_WARN_DEPRECATED is not set ++# CONFIG_ENABLE_MUST_CHECK is not set ++CONFIG_FRAME_WARN=1024 ++# CONFIG_MAGIC_SYSRQ is not set ++# CONFIG_STRIP_ASM_SYMS is not set ++# CONFIG_UNUSED_SYMBOLS is not set ++# CONFIG_DEBUG_FS is not set ++# CONFIG_HEADERS_CHECK is not set ++# CONFIG_DEBUG_SECTION_MISMATCH is not set ++# CONFIG_DEBUG_KERNEL is not set ++# CONFIG_HARDLOCKUP_DETECTOR is not set ++# CONFIG_SPARSE_RCU_POINTER is not set ++CONFIG_DEBUG_BUGVERBOSE=y ++# CONFIG_DEBUG_MEMORY_INIT is not set ++CONFIG_FRAME_POINTER=y ++# CONFIG_SYSCTL_SYSCALL_CHECK is not set ++CONFIG_HAVE_FUNCTION_TRACER=y ++CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y ++CONFIG_HAVE_DYNAMIC_FTRACE=y ++CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y ++CONFIG_HAVE_C_RECORDMCOUNT=y ++CONFIG_TRACING_SUPPORT=y ++# CONFIG_FTRACE is not set ++# CONFIG_DMA_API_DEBUG is not set ++# CONFIG_ATOMIC64_SELFTEST is not set ++# CONFIG_SAMPLES is not set ++CONFIG_HAVE_ARCH_KGDB=y ++# CONFIG_TEST_KSTRTOX is not set ++# CONFIG_STRICT_DEVMEM is not set ++# CONFIG_ARM_UNWIND is not set ++# CONFIG_DEBUG_USER is not set ++# CONFIG_OC_ETM is not set ++CONFIG_DEBUG_S3C_UART=0 ++ ++# ++# Security options ++# ++CONFIG_KEYS=y ++# CONFIG_KEYS_DEBUG_PROC_KEYS is not set ++# CONFIG_SECURITY_DMESG_RESTRICT is not set ++# CONFIG_SECURITY is not set ++# CONFIG_SECURITYFS is not set ++CONFIG_DEFAULT_SECURITY_DAC=y ++CONFIG_DEFAULT_SECURITY="" ++CONFIG_CRYPTO=y ++ ++# ++# Crypto core or helper ++# ++CONFIG_CRYPTO_ALGAPI=y ++CONFIG_CRYPTO_ALGAPI2=y ++CONFIG_CRYPTO_AEAD2=y ++CONFIG_CRYPTO_BLKCIPHER=y ++CONFIG_CRYPTO_BLKCIPHER2=y ++CONFIG_CRYPTO_HASH=y ++CONFIG_CRYPTO_HASH2=y ++CONFIG_CRYPTO_RNG2=y ++CONFIG_CRYPTO_PCOMP2=y ++CONFIG_CRYPTO_MANAGER=y ++CONFIG_CRYPTO_MANAGER2=y ++CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y ++# CONFIG_CRYPTO_GF128MUL is not set ++# CONFIG_CRYPTO_NULL is not set ++CONFIG_CRYPTO_WORKQUEUE=y ++# CONFIG_CRYPTO_CRYPTD is not set ++# CONFIG_CRYPTO_AUTHENC is not set ++# CONFIG_CRYPTO_TEST is not set ++ ++# ++# Authenticated Encryption with Associated Data ++# ++# CONFIG_CRYPTO_CCM is not set ++# CONFIG_CRYPTO_GCM is not set ++# CONFIG_CRYPTO_SEQIV is not set ++ ++# ++# Block modes ++# ++# CONFIG_CRYPTO_CBC is not set ++# CONFIG_CRYPTO_CTR is not set ++# CONFIG_CRYPTO_CTS is not set ++CONFIG_CRYPTO_ECB=y ++# CONFIG_CRYPTO_LRW is not set ++# CONFIG_CRYPTO_PCBC is not set ++# CONFIG_CRYPTO_XTS is not set ++ ++# ++# Hash modes ++# ++# CONFIG_CRYPTO_HMAC is not set ++# CONFIG_CRYPTO_XCBC is not set ++# CONFIG_CRYPTO_VMAC is not set ++ ++# ++# Digest ++# ++CONFIG_CRYPTO_CRC32C=y ++# CONFIG_CRYPTO_GHASH is not set ++# CONFIG_CRYPTO_MD4 is not set ++# CONFIG_CRYPTO_MD5 is not set ++# CONFIG_CRYPTO_MICHAEL_MIC is not set ++# CONFIG_CRYPTO_RMD128 is not set ++# CONFIG_CRYPTO_RMD160 is not set ++# CONFIG_CRYPTO_RMD256 is not set ++# CONFIG_CRYPTO_RMD320 is not set ++CONFIG_CRYPTO_SHA1=y ++# CONFIG_CRYPTO_SHA256 is not set ++# CONFIG_CRYPTO_SHA512 is not set ++# CONFIG_CRYPTO_TGR192 is not set ++# CONFIG_CRYPTO_WP512 is not set ++ ++# ++# Ciphers ++# ++CONFIG_CRYPTO_AES=y ++# CONFIG_CRYPTO_ANUBIS is not set ++CONFIG_CRYPTO_ARC4=y ++# CONFIG_CRYPTO_BLOWFISH is not set ++# CONFIG_CRYPTO_CAMELLIA is not set ++# CONFIG_CRYPTO_CAST5 is not set ++# CONFIG_CRYPTO_CAST6 is not set ++# CONFIG_CRYPTO_DES is not set ++# CONFIG_CRYPTO_FCRYPT is not set ++# CONFIG_CRYPTO_KHAZAD is not set ++# CONFIG_CRYPTO_SALSA20 is not set ++# CONFIG_CRYPTO_SEED is not set ++# CONFIG_CRYPTO_SERPENT is not set ++# CONFIG_CRYPTO_TEA is not set ++# CONFIG_CRYPTO_TWOFISH is not set ++ ++# ++# Compression ++# ++CONFIG_CRYPTO_DEFLATE=y ++# CONFIG_CRYPTO_ZLIB is not set ++CONFIG_CRYPTO_LZO=y ++ ++# ++# Random Number Generation ++# ++# CONFIG_CRYPTO_ANSI_CPRNG is not set ++# CONFIG_CRYPTO_USER_API_HASH is not set ++# CONFIG_CRYPTO_USER_API_SKCIPHER is not set ++# CONFIG_CRYPTO_HW is not set ++# CONFIG_BINARY_PRINTF is not set ++ ++# ++# Library routines ++# ++CONFIG_BITREVERSE=y ++CONFIG_CRC_CCITT=y ++CONFIG_CRC16=y ++# CONFIG_CRC_T10DIF is not set ++CONFIG_CRC_ITU_T=y ++CONFIG_CRC32=y ++CONFIG_CRC7=y ++CONFIG_LIBCRC32C=y ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++CONFIG_LZO_COMPRESS=y ++CONFIG_LZO_DECOMPRESS=y ++# CONFIG_XZ_DEC is not set ++# CONFIG_XZ_DEC_BCJ is not set ++CONFIG_TEXTSEARCH=y ++CONFIG_TEXTSEARCH_KMP=y ++CONFIG_TEXTSEARCH_BM=y ++CONFIG_TEXTSEARCH_FSM=y ++CONFIG_HAS_IOMEM=y ++CONFIG_HAS_DMA=y ++CONFIG_NLATTR=y ++CONFIG_GENERIC_ATOMIC64=y ++CONFIG_AVERAGE=y +diff -Nuar -x .gitignore linux-3.0/drivers/input/touchscreen/s3c2410_ts.c linux-3.0-fl2440/drivers/input/touchscreen/s3c2410_ts.c +--- linux-3.0/drivers/input/touchscreen/s3c2410_ts.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/input/touchscreen/s3c2410_ts.c 2020-01-09 16:54:31.277380204 +0800 +@@ -126,6 +126,7 @@ + input_report_abs(ts.input, ABS_Y, ts.yp); + + input_report_key(ts.input, BTN_TOUCH, 1); ++ input_report_abs(ts.input, ABS_PRESSURE, 1); /* Add by guowenxue, 2012.03.30 */ + input_sync(ts.input); + + ts.xp = 0; +@@ -140,6 +141,7 @@ + ts.count = 0; + + input_report_key(ts.input, BTN_TOUCH, 0); ++ input_report_abs(ts.input, ABS_PRESSURE, 0); /* Add by guowenxue, 2012.03.30 */ + input_sync(ts.input); + + writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC); +@@ -314,10 +316,11 @@ + } + + ts.input = input_dev; +- ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); ++ ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT(EV_SYN); /* Modify by guowenxue, 2012.03.30 */ + ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0); + input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0); ++ input_set_abs_params(ts.input, ABS_PRESSURE, 0, 1, 0, 0); /* Add by guowenxue, 2012.03.30 */ + + ts.input->name = "S3C24XX TouchScreen"; + ts.input->id.bustype = BUS_HOST; +diff -Nuar -x .gitignore linux-3.0/drivers/mmc/host/s3cmci.c linux-3.0-fl2440/drivers/mmc/host/s3cmci.c +--- linux-3.0/drivers/mmc/host/s3cmci.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/mmc/host/s3cmci.c 2020-01-09 16:54:31.277380204 +0800 +@@ -1275,6 +1275,7 @@ + + writel(mci_con, host->base + S3C2410_SDICON); + ++#if 0 /*Comment by guowenxue, remove the noisy debug output*/ + if ((ios->power_mode == MMC_POWER_ON) || + (ios->power_mode == MMC_POWER_UP)) { + dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n", +@@ -1282,6 +1283,7 @@ + } else { + dbg(host, dbg_conf, "powered down.\n"); + } ++#endif + + host->bus_width = ios->bus_width; + } +@@ -1357,11 +1359,16 @@ + .enable_sdio_irq = s3cmci_enable_sdio_irq, + }; + ++/*Change s3cmci_def_pdata by guowenxue, 2011.09.06*/ + static struct s3c24xx_mci_pdata s3cmci_def_pdata = { + /* This is currently here to avoid a number of if (host->pdata) + * checks. Any zero fields to ensure reasonable defaults are picked. */ +- .no_wprotect = 1, +- .no_detect = 1, ++ .gpio_detect = S3C2410_GPG(10), /* NCD(NCD_SD) pin use EINT18/GPG10*/ ++ .gpio_wprotect = S3C2410_GPH(8), /*WP(WP_SD) pin use GPH8*/ ++ .ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34, ++ .wprotect_invert = 0, ++ .detect_invert = 0, ++ .set_power = NULL, + }; + + #ifdef CONFIG_CPU_FREQ +diff -Nuar -x .gitignore linux-3.0/drivers/net/dm9000.c linux-3.0-fl2440/drivers/net/dm9000.c +--- linux-3.0/drivers/net/dm9000.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/net/dm9000.c 2020-01-09 16:54:31.277380204 +0800 +@@ -39,6 +39,10 @@ + #include <asm/irq.h> + #include <asm/io.h> + ++#include <mach/regs-gpio.h> //add by guowenxue, 2011.08.30 ++#include <mach/irqs.h> ++#include <mach/hardware.h> ++ + #include "dm9000.h" + + /* Board/System/Debug information/definition ---------------- */ +@@ -1144,7 +1148,12 @@ + dm9000_open(struct net_device *dev) + { + board_info_t *db = netdev_priv(dev); +- unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; ++ unsigned long irqflags; ++ ++ /* Modified by guowenxue, 2011.08.30 */ ++ db->irq_res->flags |= IRQ_TYPE_EDGE_RISING; ++ irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; ++ irq_set_irq_type(dev->irq, IRQ_TYPE_EDGE_RISING); + + if (netif_msg_ifup(db)) + dev_dbg(db->dev, "enabling %s\n", dev->name); +diff -Nuar -x .gitignore linux-3.0/drivers/tty/serial/samsung.c linux-3.0-fl2440/drivers/tty/serial/samsung.c +--- linux-3.0/drivers/tty/serial/samsung.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/tty/serial/samsung.c 2020-01-09 16:54:31.297380204 +0800 +@@ -54,7 +54,7 @@ + + /* UART name and device definitions */ + +-#define S3C24XX_SERIAL_NAME "ttySAC" ++#define S3C24XX_SERIAL_NAME "ttyS" /*Modified by guowenxue, 2011.08.30*/ + #define S3C24XX_SERIAL_MAJOR 204 + #define S3C24XX_SERIAL_MINOR 64 + +@@ -882,7 +882,7 @@ + + static struct uart_driver s3c24xx_uart_drv = { + .owner = THIS_MODULE, +- .driver_name = "s3c2410_serial", ++ .driver_name = "ttyS", /*Modified by guowenxue, 2011.08.30*/ + .nr = CONFIG_SERIAL_SAMSUNG_UARTS, + .cons = S3C24XX_SERIAL_CONSOLE, + .dev_name = S3C24XX_SERIAL_NAME, +diff -Nuar -x .gitignore linux-3.0/drivers/tty/vt/vt.c linux-3.0-fl2440/drivers/tty/vt/vt.c +--- linux-3.0/drivers/tty/vt/vt.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/tty/vt/vt.c 2020-01-09 16:54:31.297380204 +0800 +@@ -3843,12 +3843,14 @@ + */ + static void blank_screen_t(unsigned long dummy) + { ++#if 0 /* Comment by guowenxue, don't shutdown the LCD */ + if (unlikely(!keventd_up())) { + mod_timer(&console_timer, jiffies + (blankinterval * HZ)); + return; + } + blank_timer_expired = 1; + schedule_work(&console_work); ++#endif + } + + void poke_blanked_console(void) +diff -Nuar -x .gitignore linux-3.0/drivers/usb/host/ohci-s3c2410.c linux-3.0-fl2440/drivers/usb/host/ohci-s3c2410.c +--- linux-3.0/drivers/usb/host/ohci-s3c2410.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/usb/host/ohci-s3c2410.c 2020-01-09 16:54:31.297380204 +0800 +@@ -22,6 +22,7 @@ + #include <linux/platform_device.h> + #include <linux/clk.h> + #include <plat/usb-control.h> ++#include <mach/regs-clock.h> /* Add by guowenxue, 2012.04.01 */ + + #define valid_port(idx) ((idx) == 1 || (idx) == 2) + +@@ -45,6 +46,15 @@ + { + struct s3c2410_hcd_info *info = dev->dev.platform_data; + ++ /* Add by guowenxue 2012.04.01, fix device descriptor read/64, error -62 bug, value refer to datasheet P255 */ ++ unsigned long upllvalue = (0x38<<12)|(0x02<<4)|(0x02); ++ while (upllvalue != __raw_readl(S3C2410_UPLLCON)) ++ { ++ __raw_writel(upllvalue, S3C2410_UPLLCON); ++ mdelay(1); ++ } ++ __raw_writel(upllvalue, S3C2410_UPLLCON); ++ + dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); + + clk_enable(usb_clk); +diff -Nuar -x .gitignore linux-3.0/drivers/usb/serial/Kconfig linux-3.0-fl2440/drivers/usb/serial/Kconfig +--- linux-3.0/drivers/usb/serial/Kconfig 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/usb/serial/Kconfig 2020-01-09 16:54:31.297380204 +0800 +@@ -588,7 +588,8 @@ + module will be called keyspan_pda. + + config USB_SERIAL_WWAN +- tristate ++ boolean ++ default y if USB_SERIAL_OPTION + + config USB_SERIAL_OPTION + tristate "USB driver for GSM and CDMA modems" +diff -Nuar -x .gitignore linux-3.0/drivers/usb/serial/option.c linux-3.0-fl2440/drivers/usb/serial/option.c +--- linux-3.0/drivers/usb/serial/option.c 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/drivers/usb/serial/option.c 2020-01-09 16:54:31.301380204 +0800 +@@ -51,6 +51,13 @@ + static void option_instat_callback(struct urb *urb); + + /* Vendor and product IDs */ ++static int vendor = 0; /* Add by guowenxue */ ++static int product = 0; /* Add by guowenxue */ ++ ++/* Vendor and product IDs */ ++#define OPTION_VENDOR_RESERVED 0xFFFF /* Add by guowenxue */ ++#define OPTION_RESERVED_DEVICE 0xFFFF /* Add by guowenxue */ ++ + #define OPTION_VENDOR_ID 0x0AF0 + #define OPTION_PRODUCT_COLT 0x5000 + #define OPTION_PRODUCT_RICOLA 0x6000 +@@ -446,7 +453,8 @@ + .reason = OPTION_BLACKLIST_SENDSETUP + }; + +-static const struct usb_device_id option_ids[] = { ++static struct usb_device_id option_ids[] = { ++ { USB_DEVICE(OPTION_VENDOR_RESERVED, OPTION_RESERVED_DEVICE) }, /* Add by guowenxue */ + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, + { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) }, +@@ -633,6 +641,7 @@ + { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC650) }, + { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ ++ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* ZTE AC8700 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ + { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, +@@ -1079,6 +1088,15 @@ + static int __init option_init(void) + { + int retval; ++ ++ if ((vendor>0) && (product>0)) ++ { ++ option_ids[0].match_flags = USB_DEVICE_ID_MATCH_DEVICE; ++ option_ids[0].idVendor = vendor; ++ option_ids[0].idProduct = product; ++ printk("Register option drvier for modem vendor=0x%04x product=0x%04x\n", vendor, product); ++ } ++ + retval = usb_serial_register(&option_1port_device); + if (retval) + goto failed_1port_device_register; +@@ -1252,6 +1270,12 @@ + 0x22, 0x21, val, ifNum, NULL, 0, USB_CTRL_SET_TIMEOUT); + } + ++/* vendor and product option add by guowenxue */ ++module_param(vendor, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(vendor, "User specified vendor ID"); ++module_param(product, int, S_IRUGO | S_IWUSR); ++MODULE_PARM_DESC(product, "User specified product ID"); ++ + MODULE_AUTHOR(DRIVER_AUTHOR); + MODULE_DESCRIPTION(DRIVER_DESC); + MODULE_VERSION(DRIVER_VERSION); +diff -Nuar -x .gitignore linux-3.0/Makefile linux-3.0-fl2440/Makefile +--- linux-3.0/Makefile 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/Makefile 2020-01-09 17:26:42.517417250 +0800 +@@ -144,7 +144,7 @@ + # but instead _all depend on modules + PHONY += all + ifeq ($(KBUILD_EXTMOD),) +-_all: all ++_all: all + else + _all: modules + endif +@@ -192,8 +192,8 @@ + # Default value for CROSS_COMPILE is not to prefix executables + # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile + export KBUILD_BUILDHOST := $(SUBARCH) +-ARCH ?= $(SUBARCH) +-CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) ++ARCH ?= arm ++CROSS_COMPILE ?= /opt/xtools/arm920t/bin/arm-linux- + + # Architecture as present in compile.h + UTS_MACHINE := $(ARCH) +@@ -557,6 +557,8 @@ + # This allow a user to issue only 'make' to build a kernel including modules + # Defaults to vmlinux, but the arch makefile usually adds further targets + all: vmlinux ++ mkimage -A arm -O linux -T kernel -C none -a 30008000 -e 30008040 -n "Linux Kernel" -d arch/arm/boot/zImage linuxrom-fl2440.bin ++ chmod a+x linuxrom-fl2440.bin + + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE + KBUILD_CFLAGS += -Os +@@ -1201,6 +1203,7 @@ + -o -name '.*.rej' -o -size 0 \ + -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ + -type f -print | xargs rm -f ++ @rm -f linuxrom-*.bin + + + # Packaging of the kernel to various formats +diff -Nuar -x .gitignore linux-3.0/net/wireless/db.txt linux-3.0-fl2440/net/wireless/db.txt +--- linux-3.0/net/wireless/db.txt 2011-07-22 10:17:23.000000000 +0800 ++++ linux-3.0-fl2440/net/wireless/db.txt 2020-01-09 16:54:31.301380204 +0800 +@@ -1,17 +1,793 @@ +-# +-# This file is a placeholder to prevent accidental build breakage if someone +-# enables CONFIG_CFG80211_INTERNAL_REGDB. Almost no one actually needs to +-# enable that build option. +-# +-# You should be using CRDA instead. It is even better if you use the CRDA +-# package provided by your distribution, since they will probably keep it +-# up-to-date on your behalf. +-# +-# If you _really_ intend to use CONFIG_CFG80211_INTERNAL_REGDB then you will +-# need to replace this file with one containing appropriately formatted +-# regulatory rules that cover the regulatory domains you will be using. Your +-# best option is to extract the db.txt file from the wireless-regdb git +-# repository: +-# +-# git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-regdb.git +-# ++# This is the world regulatory domain ++country 00: ++ (2402 - 2472 @ 40), (3, 20) ++ # Channel 12 - 13. ++ (2457 - 2482 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS ++ # Channel 14. Only JP enables this and for 802.11b only ++ (2474 - 2494 @ 20), (3, 20), PASSIVE-SCAN, NO-IBSS, NO-OFDM ++ # Channel 36 - 48 ++ (5170 - 5250 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS ++ # NB: 5260 MHz - 5700 MHz requies DFS ++ # Channel 149 - 165 ++ (5735 - 5835 @ 40), (3, 20), PASSIVE-SCAN, NO-IBSS ++ ++ ++country AD: ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country AE: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country AL: ++ (2402 - 2482 @ 20), (N/A, 20) ++ ++country AM: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (N/A, 18) ++ (5250 - 5330 @ 20), (N/A, 18), DFS ++ ++country AN: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country AR: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country AT: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country AU: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 23) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country AW: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country AZ: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 18) ++ (5250 - 5330 @ 40), (N/A, 18), DFS ++ ++country BA: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country BB: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 23) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country BD: ++ (2402 - 2482 @ 40), (N/A, 20) ++ ++country BE: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country BG: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 23) ++ (5250 - 5290 @ 40), (N/A, 23), DFS ++ (5490 - 5710 @ 40), (N/A, 30), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country BH: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (N/A, 20) ++ (5250 - 5330 @ 20), (N/A, 20), DFS ++ (5735 - 5835 @ 20), (N/A, 20) ++ ++country BL: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 18) ++ (5250 - 5330 @ 40), (N/A, 18), DFS ++ ++country BN: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country BO: ++ (2402 - 2482 @ 40), (N/A, 30) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country BR: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country BY: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country BZ: ++ (2402 - 2482 @ 40), (N/A, 30) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country CA: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country CH: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country CL: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5735 - 5835 @ 40), (N/A, 20) ++ ++country CN: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ # 60 gHz band channels 1,4: 28dBm, channels 2,3: 44dBm ++ # ref: http://www.miit.gov.cn/n11293472/n11505629/n11506593/n11960250/n11960606/n11960700/n12330791.files/n12330790.pdf ++ (57240 - 59400 @ 2160), (N/A, 28) ++ (59400 - 63720 @ 2160), (N/A, 44) ++ (63720 - 65880 @ 2160), (N/A, 28) ++ ++country CO: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country CR: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (3, 17) ++ (5250 - 5330 @ 20), (3, 23), DFS ++ (5735 - 5835 @ 20), (3, 30) ++ ++country CS: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country CY: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++# Data from http://www.ctu.eu/164/download/VOR/VOR-12-08-2005-34.pdf ++# and http://www.ctu.eu/164/download/VOR/VOR-12-05-2007-6-AN.pdf ++# Power at 5250 - 5350 MHz and 5470 - 5725 MHz can be doubled if TPC is ++# implemented. ++country CZ: DFS-ETSI ++ (2400 - 2483.5 @ 40), (N/A, 100 mW) ++ (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR ++ (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS ++ (5470 - 5725 @ 40), (N/A, 500 mW), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from ++# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf ++# For the 5GHz range also see ++# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38216/publicationFile/6579/WLAN5GHzVfg7_2010_28042010pdf.pdf ++# The values have been reduced by a factor of 2 (3db) for non TPC devices ++# (in other words: devices with TPC can use twice the tx power of this table). ++# Note that the docs do not require TPC for 5150--5250; the reduction to ++# 100mW thus is not strictly required -- however the conservative 100mW ++# limit is used here as the non-interference with radar and satellite ++# apps relies on the attenuation by the building walls only in the ++# absence of DFS; the neighbour countries have 100mW limit here as well. ++ ++country DE: DFS-ETSI ++ # entries 279004 and 280006 ++ (2400 - 2483.5 @ 40), (N/A, 100 mW) ++ # entry 303005 ++ (5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR ++ # entries 304002 and 305002 ++ (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS ++ # entries 308002, 309001 and 310003 ++ (5470 - 5725 @ 40), (N/A, 500 mW), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country DK: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country DO: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country DZ: ++ (2402 - 2482 @ 40), (N/A, 20) ++ ++country EC: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (3, 17) ++ (5250 - 5330 @ 20), (3, 23), DFS ++ (5735 - 5835 @ 20), (3, 30) ++ ++country EE: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country EG: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (N/A, 20) ++ (5250 - 5330 @ 20), (N/A, 20), DFS ++ ++country ES: DFS-ETSI ++ (2400 - 2483.5 @ 40), (N/A, 100 mW) ++ (5150 - 5250 @ 40), (N/A, 100 mW), NO-OUTDOOR ++ (5250 - 5350 @ 40), (N/A, 100 mW), NO-OUTDOOR, DFS ++ (5470 - 5725 @ 40), (N/A, 500 mW), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country FI: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country FR: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country GE: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 18) ++ (5250 - 5330 @ 40), (N/A, 18), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country GB: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country GD: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country GR: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country GL: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (N/A, 20) ++ (5250 - 5330 @ 20), (N/A, 20), DFS ++ (5490 - 5710 @ 20), (N/A, 27), DFS ++ ++country GT: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country GU: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 20), (3, 17) ++ (5250 - 5330 @ 20), (3, 23), DFS ++ (5735 - 5835 @ 20), (3, 30) ++ ++country HN: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country HK: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country HR: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country HT: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country HU: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country ID: ++ (2402 - 2482 @ 40), (N/A, 20) ++ ++country IE: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country IL: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5150 - 5250 @ 40), (N/A, 200 mW), NO-OUTDOOR ++ (5250 - 5350 @ 40), (N/A, 200 mW), NO-OUTDOOR, DFS ++ ++country IN: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5735 - 5835 @ 40), (N/A, 20) ++ ++country IS: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country IR: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country IT: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country JM: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country JP: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (2474 - 2494 @ 20), (N/A, 20), NO-OFDM ++ (4910 - 4990 @ 40), (N/A, 23) ++ (5030 - 5090 @ 40), (N/A, 23) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 23), DFS ++ ++country JO: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 18) ++ ++country KE: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country KH: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country KP: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5330 @ 40), (3, 20) ++ (5160 - 5250 @ 40), (3, 20), DFS ++ (5490 - 5630 @ 40), (3, 30), DFS ++ (5735 - 5815 @ 40), (3, 30) ++ ++country KR: ++ (2402 - 2482 @ 20), (N/A, 20) ++ (5170 - 5250 @ 20), (3, 20) ++ (5250 - 5330 @ 20), (3, 20), DFS ++ (5490 - 5630 @ 20), (3, 30), DFS ++ (5735 - 5815 @ 20), (3, 30) ++ ++country KW: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ ++country KZ: ++ (2402 - 2482 @ 40), (N/A, 20) ++ ++country LB: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country LI: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ ++country LK: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (3, 17) ++ (5250 - 5330 @ 20), (3, 20), DFS ++ (5490 - 5710 @ 20), (3, 20), DFS ++ (5735 - 5835 @ 20), (3, 30) ++ ++country LT: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country LU: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country LV: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country MC: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 18) ++ (5250 - 5330 @ 40), (N/A, 18), DFS ++ ++country MA: ++ (2402 - 2482 @ 40), (N/A, 20) ++ ++country MO: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 23) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country MK: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country MT: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country MY: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 30), DFS ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country MX: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country NL: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20), NO-OUTDOOR ++ (5250 - 5330 @ 40), (N/A, 20), NO-OUTDOOR, DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country NO: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country NP: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country NZ: ++ (2402 - 2482 @ 40), (N/A, 30) ++ (5170 - 5250 @ 20), (3, 23) ++ (5250 - 5330 @ 20), (3, 23), DFS ++ (5735 - 5835 @ 20), (3, 30) ++ ++country OM: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country PA: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country PE: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country PG: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country PH: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country PK: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country PL: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country PT: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country PR: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 23), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country QA: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country RO: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country RS: ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country RU: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 20), (N/A, 30) ++ ++country RW: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5835 @ 40), (N/A, 30) ++ ++country SA: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (3, 23) ++ (5250 - 5330 @ 20), (3, 23), DFS ++ (5735 - 5835 @ 20), (3, 30) ++ ++country SE: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country SG: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5735 - 5835 @ 40), (N/A, 20) ++ ++country SI: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country SK: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ (5490 - 5710 @ 40), (N/A, 27), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country SV: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (3, 17) ++ (5250 - 5330 @ 20), (3, 23), DFS ++ (5735 - 5835 @ 20), (3, 30) ++ ++country SY: ++ (2402 - 2482 @ 40), (N/A, 20) ++ ++country TW: ++ (2402 - 2472 @ 40), (3, 27) ++ (5270 - 5330 @ 40), (3, 17), DFS ++ (5735 - 5815 @ 40), (3, 30) ++ ++country TH: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country TT: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country TN: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (N/A, 20) ++ (5250 - 5330 @ 20), (N/A, 20), DFS ++ ++country TR: DFS-ETSI ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 20), (N/A, 20) ++ (5250 - 5330 @ 20), (N/A, 20), DFS ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++# Source: ++# #914 / 06 Sep 2007: http://www.ucrf.gov.ua/uk/doc/nkrz/1196068874 ++# #1174 / 23 Oct 2008: http://www.nkrz.gov.ua/uk/activities/ruling/1225269361 ++# (appendix 8) ++# Listed 5GHz range is a lowest common denominator for all related ++# rules in the referenced laws. Such a range is used because of ++# disputable definitions there. ++country UA: ++ (2400 - 2483.5 @ 40), (N/A, 20), NO-OUTDOOR ++ (5150 - 5350 @ 40), (N/A, 20), NO-OUTDOOR ++ # 60 gHz band channels 1-4, ref: Etsi En 302 567 ++ (57240 - 65880 @ 2160), (N/A, 40), NO-OUTDOOR ++ ++country US: DFS-FCC ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5600 @ 40), (3, 20), DFS ++ (5650 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ # 60g band ++ # reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255 ++ # channels 1,2,3, EIRP=40dBm(43dBm peak) ++ (57240 - 63720 @ 2160), (N/A, 40) ++ ++country UY: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country UZ: ++ (2402 - 2472 @ 40), (3, 27) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country VE: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5735 - 5815 @ 40), (N/A, 23) ++ ++country VN: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (N/A, 20) ++ (5250 - 5330 @ 40), (N/A, 20), DFS ++ ++country YE: ++ (2402 - 2482 @ 40), (N/A, 20) ++ ++country ZA: ++ (2402 - 2482 @ 40), (N/A, 20) ++ (5170 - 5250 @ 40), (3, 17) ++ (5250 - 5330 @ 40), (3, 20), DFS ++ (5490 - 5710 @ 40), (3, 20), DFS ++ (5735 - 5835 @ 40), (3, 30) ++ ++country ZW: ++ (2402 - 2482 @ 40), (N/A, 20) ++ diff --git a/linux-bsp/patches/u-boot-2010.09-fl2440.patch b/linux-bsp/patches/u-boot-2010.09-fl2440.patch new file mode 100644 index 0000000..50de68b --- /dev/null +++ b/linux-bsp/patches/u-boot-2010.09-fl2440.patch @@ -0,0 +1,2075 @@ +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/speed.c +--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/speed.c 2020-01-09 17:22:17.705412170 +0800 +@@ -64,6 +64,11 @@ + p = ((r & 0x003F0) >> 4) + 2; + s = r & 0x3; + ++#if defined(CONFIG_S3C2440) /* Add by guowenxue*/ ++ if (pllreg == MPLL) ++ return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s)); ++ else if (pllreg == UPLL) ++#endif /* Add end*/ + return (CONFIG_SYS_CLK_FREQ * m) / (p << s); + } + +@@ -78,7 +83,22 @@ + { + struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); + ++#if defined(CONFIG_S3C2440) ++ if (readl(&clk_power->CLKDIVN) & 0x6) ++ { ++ if ((readl(&clk_power->CLKDIVN) & 0x6)==2) ++ return(get_FCLK()/2); ++ if ((readl(&clk_power->CLKDIVN) & 0x6)==6) ++ return((readl(&clk_power->CAMDIVN) & 0x100) ? get_FCLK()/6 : get_FCLK()/3); ++ if ((readl(&clk_power->CLKDIVN) & 0x6)==4) ++ return((readl(&clk_power->CAMDIVN) & 0x200) ? get_FCLK()/8 : get_FCLK()/4); ++ return(get_FCLK()); ++ } ++ else ++ return(get_FCLK()); ++#else + return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK(); ++#endif + } + + /* return PCLK frequency */ +@@ -95,4 +115,17 @@ + return get_PLLCLK(UPLL); + } + ++ ++#if defined(CONFIG_DISPLAY_CPUINFO) ++int print_cpuinfo(void) ++{ ++ printf("S3C2440A CPU clock : %lu MHz\n", get_FCLK()); ++ printf("S3C2440A HSB clock : %lu MHz\n", get_HCLK()); ++ printf("S3C2440A PSB clock : %lu MHz\n", get_PCLK()); ++ printf("S3C2440A USB clock : %lu MHz\n", get_FCLK()); ++ ++ return 0; ++} ++#endif ++ + #endif /* CONFIG_S3C24X0 */ +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/timer.c +--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/s3c24x0/timer.c 2020-01-09 17:22:17.705412170 +0800 +@@ -181,6 +181,7 @@ + tbclk = timer_load_val * 100; + #elif defined(CONFIG_SBC2410X) || \ + defined(CONFIG_SMDK2410) || \ ++ defined(CONFIG_FL2440) || \ + defined(CONFIG_VCMA9) + tbclk = CONFIG_SYS_HZ; + #else +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/start.S u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/start.S +--- u-boot-2010.09/arch/arm/cpu/arm920t/start.S 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/start.S 2020-01-09 17:22:17.705412170 +0800 +@@ -114,8 +114,8 @@ + orr r0, r0, #0xd3 + msr cpsr, r0 + +- bl coloured_LED_init +- bl red_LED_on ++ @bl coloured_LED_init ++ @bl red_LED_on + + #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) + /* +@@ -159,13 +159,63 @@ + ldr r1, =0x3ff + ldr r0, =INTSUBMSK + str r1, [r0] ++#elif defined CONFIG_S3C2440 ++ ldr r1, =0x7fff ++ ldr r0, =INTSUBMSK ++ str r1, [r0] + # endif + ++# if defined(CONFIG_S3C2440) ++#define GPBCON 0x56000010 ++#define GPBDAT 0x56000014 ++#define GPBUP 0x56000018 ++ /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/ ++ ldr r0, =GPBCON ++ ldr r1, [r0] ++ bic r1, r1, #0x3c00 /*Set GPBCON for GPIO5,GPIO6 as 0x00 */ ++ orr r1, r1, #0x1400 /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/ ++ bic r1, r1, #0x00330000 /*Set GPBCON for GPIO8,GPIO10 as 0x00*/ ++ orr r1, r1, #0x00110000 /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/ ++ str r1, [r0] ++ ++ /*Set internal pullup resister*/ ++ ldr r0, =GPBUP ++ ldr r1, [r0] ++ orr r1, r1, #0x0560 /*Set bit 5,6,8,10, disable pullup resister*/ ++ str r1, [r0] ++ ++ ldr r2, =GPBDAT ++ ldr r3, [r2] ++ orr r3, r3, #0x0560 /*Set bit 5,6,8,10 as high level, Turn Off LED*/ ++ str r3, [r2] ++ ++# define MPLLCON 0x4C000004 ++# define MDIV_405 0x7f << 12 ++# define PSDIV_405 0x21 ++ ++ ++ /* FCLK:HCLK:PCLK = 1:4:8 */ ++ ldr r0, =CLKDIVN ++ mov r1, #0x05 ++ str r1, [r0] ++ ++ mrc p15, 0, r1, c1, c0, 0 ++ orr r1, r1, #0xc0000000 ++ mcr p15, 0, r1, c1, c0, 0 ++ ++ Ldr r0,=MPLLCON ++ mov r1, #MDIV_405 ++ add r1, r1, #PSDIV_405 ++ str r1, [r0] ++ ++ ++#else /*S3C2410, S3C2440 */ + /* FCLK:HCLK:PCLK = 1:2:4 */ + /* default FCLK is 120 MHz ! */ + ldr r0, =CLKDIVN + mov r1, #3 + str r1, [r0] ++#endif /* end of if defined(CONFIG_S3C2440) */ + #endif /* CONFIG_S3C24X0 */ + + /* +@@ -183,6 +233,92 @@ + cmp r0, r1 /* don't reloc during debug */ + beq stack_setup + ++judgment_norflash_nandflash_boot: ++ ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) ++ mov r0, #0 ++ str r0, [r1] ++ ++ mov r1, #0x3c ++ ldr r0, [r1] ++ cmp r0, #0 ++ bne norflash_boot ++ ++ /*Nandflash boot going here, recovery address 0x0000003C date*/ ++ ldr r0, =(0xdeadbeef) ++ ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) ++ str r0, [r1] ++ ++nandflash_boot: ++#define LENGTH_UBOOT 0x60000 ++#define NAND_CTL_BASE 0x4E000000 ++/* Offset */ ++#define oNFCONF 0x00 ++#define oNFCONT 0x04 ++#define oNFCMD 0x08 ++#define oNFSTAT 0x20 ++ ++ mov r1, #NAND_CTL_BASE ++ ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) ++ str r2, [r1, #oNFCONF] ++ ldr r2, [r1, #oNFCONF] ++ ++ ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control ++ str r2, [r1, #oNFCONT] ++ ldr r2, [r1, #oNFCONT] ++ ++ ldr r2, =(0x6) @ RnB Clear ++ str r2, [r1, #oNFSTAT] ++ ldr r2, [r1, #oNFSTAT] ++ ++ mov r2, #0xff @ RESET command ++ strb r2, [r1, #oNFCMD] ++ ++ mov r3, #0 @ wait ++nand_delay: ++ add r3, r3, #0x1 ++ cmp r3, #0xa ++ blt nand_delay ++ ++nand_wait: ++ ldr r2, [r1, #oNFSTAT] @ wait ready ++ tst r2, #0x4 ++ beq nand_wait ++ ++ ldr r2, [r1, #oNFCONT] ++ orr r2, r2, #0x2 @ Flash Memory Chip Disable ++ str r2, [r1, #oNFCONT] ++ ++ ldr sp, DW_STACK_START @ setup stack pointer ++ mov fp, #0 @ no previous frame, so fp=0 ++ ++ ldr r0, =TEXT_BASE ++ mov r1, #0x0 ++ mov r2, #LENGTH_UBOOT ++ bl nand_read_ll ++ tst r0, #0x0 ++ bne infinite_loop /*nand_read_ll() not return 0, then goto dead loop*/ ++ ++nand_read_ok: ++ /*Then verify the read data validation*/ ++ mov r0, #0 ++ ldr r1, =TEXT_BASE ++ mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes ++ ++compare_next_byte: ++ ldr r3, [r0], #4 ++ ldr r4, [r1], #4 ++ teq r3, r4 ++ bne infinite_loop ++ ++ subs r2, r2, #4 ++ beq stack_setup ++ bne compare_next_byte ++ ++infinite_loop: ++ b infinite_loop @ infinite loop ++ ++norflash_boot: ++ + ldr r2, _armboot_start + ldr r3, _bss_start + sub r2, r3, r2 /* r2 <- size of armboot */ +@@ -216,10 +352,22 @@ + cmp r0, r1 + ble clbss_l + ++ ldr r1, =GPBDAT ++ ldr r2, [r1] ++ bic r2, r2, #(1<<5) ++ str r2, [r1] ++ + ldr pc, _start_armboot + + _start_armboot: .word start_armboot + ++#ifdef CONFIG_S3C24X0 ++#define STACK_BASE 0x33f00000 ++#define STACK_SIZE 0x10000 ++ .align 2 ++ DW_STACK_START: .word STACK_BASE+STACK_SIZE-4 ++#endif ++ + + /* + ************************************************************************* +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/u-boot.lds +--- u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/arch/arm/cpu/arm920t/u-boot.lds 2020-01-09 17:22:17.705412170 +0800 +@@ -40,6 +40,8 @@ + .text : + { + arch/arm/cpu/arm920t/start.o (.text) ++ board/lingyun/fl2440/lowlevel_init.o (.text) ++ board/lingyun/fl2440/nand_read.o (.text) + *(.text) + } + +diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h +--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h 2020-01-09 17:22:17.705412170 +0800 +@@ -20,7 +20,7 @@ + + #ifdef CONFIG_S3C2400 + #include <asm/arch/s3c2400.h> +-#elif defined CONFIG_S3C2410 ++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + #include <asm/arch/s3c2410.h> + #else + #error Please define the s3c24x0 cpu type +diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h +--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h 2020-01-09 17:22:17.705412170 +0800 +@@ -78,7 +78,7 @@ + u32 PRIORITY; + u32 INTPND; + u32 INTOFFSET; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 SUBSRCPND; + u32 INTSUBMSK; + #endif +@@ -88,11 +88,11 @@ + /* DMAS (see manual chapter 8) */ + struct s3c24x0_dma { + u32 DISRC; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 DISRCC; + #endif + u32 DIDST; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 DIDSTC; + #endif + u32 DCON; +@@ -103,7 +103,7 @@ + #ifdef CONFIG_S3C2400 + u32 res[1]; + #endif +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 res[7]; + #endif + }; +@@ -122,6 +122,9 @@ + u32 CLKCON; + u32 CLKSLOW; + u32 CLKDIVN; ++#if defined (CONFIG_S3C2440) ++ u32 CAMDIVN; ++#endif + }; + + +@@ -141,7 +144,7 @@ + u32 res[8]; + u32 DITHMODE; + u32 TPAL; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 LCDINTPND; + u32 LCDSRCPND; + u32 LCDINTMSK; +@@ -151,6 +154,7 @@ + + + /* NAND FLASH (see S3C2410 manual chapter 6) */ ++#if defined(CONFIG_S3C2410) + struct s3c2410_nand { + u32 NFCONF; + u32 NFCMD; +@@ -159,6 +163,26 @@ + u32 NFSTAT; + u32 NFECC; + }; ++#elif defined (CONFIG_S3C2440) ++struct s3c2410_nand { ++ u32 NFCONF; ++ u32 NFCONT; ++ u32 NFCMD; ++ u32 NFADDR; ++ u32 NFDATA; ++ u32 NFMECCD0; ++ u32 NFMECCD1; ++ u32 NFSECCD; ++ u32 NFSTAT; ++ u32 NFESTAT0; ++ u32 NFESTAT1; ++ u32 NFMECC0; ++ u32 NFMECC1; ++ u32 NFSECC; ++ u32 NFSBLK; ++ u32 NFEBLK; ++}; ++#endif + + + /* UART (see manual chapter 11) */ +@@ -397,7 +421,7 @@ + u32 MISCCR; + u32 EXTINT; + #endif +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 GPACON; + u32 GPADAT; + u32 res1[2]; +@@ -446,6 +470,13 @@ + u32 GSTATUS2; + u32 GSTATUS3; + u32 GSTATUS4; ++#if defined (CONFIG_S3C2440) ++ u32 res9[3]; ++ u32 MSLCON; ++ u32 GPJCON; ++ u32 GPJDAT; ++ u32 GPJUP; ++#endif + #endif + }; + +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/config.mk u-boot-2010.09-fl2440/board/lingyun/fl2440/config.mk +--- u-boot-2010.09/board/lingyun/fl2440/config.mk 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/config.mk 2020-01-09 17:22:17.705412170 +0800 +@@ -0,0 +1,25 @@ ++# ++# (C) Copyright 2002 ++# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> ++# David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> ++# ++# SAMSUNG SMDK2410 board with S3C2410X (ARM920T) cpu ++# ++# see http://www.samsung.com/ for more information on SAMSUNG ++# ++ ++# ++# SMDK2410 has 1 bank of 64 MB DRAM ++# ++# 3000'0000 to 3400'0000 ++# ++# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000 ++# optionally with a ramdisk at 3080'0000 ++# ++# we load ourself to 33F8'0000 ++# ++# download area is 3300'0000 ++# ++ ++ ++TEXT_BASE = 0x33F80000 +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-fl2440/board/lingyun/fl2440/fl2440.c +--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/fl2440.c 2020-01-09 17:22:17.705412170 +0800 +@@ -0,0 +1,174 @@ ++/* ++ * (C) Copyright 2002 ++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com> ++ * Marius Groeger <mgroeger@sysgo.de> ++ * ++ * (C) Copyright 2002 ++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 <common.h> ++#include <netdev.h> ++#include <asm/arch/s3c24x0_cpu.h> ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define FCLK_SPEED 1 ++ ++#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */ ++#define M_MDIV 0xC3 ++#define M_PDIV 0x4 ++#define M_SDIV 0x1 ++#elif FCLK_SPEED==1 /* Fout = 405MHz, modify by guowenxue */ ++#define M_MDIV 0x7f ++#define M_PDIV 0x2 ++#define M_SDIV 0x1 ++#endif ++ ++#define USB_CLOCK 1 ++ ++#if USB_CLOCK==0 ++#define U_M_MDIV 0xA1 ++#define U_M_PDIV 0x3 ++#define U_M_SDIV 0x1 ++#elif USB_CLOCK==1 ++#define U_M_MDIV 0x38 /* Modify by guowenxue */ ++#define U_M_PDIV 0x3 ++#define U_M_SDIV 0x2 ++#endif ++ ++static inline void delay (unsigned long loops) ++{ ++ __asm__ volatile ("1:\n" ++ "subs %0, %1, #1\n" ++ "bne 1b":"=r" (loops):"0" (loops)); ++} ++ ++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */ ++#define BEEP 0 /* Buzzer use GPB0 */ ++#define DELAY_TIME 10000000 ++ ++void turn_beep(void) ++{ ++ int count = 2; ++ struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio(); ++ ++ gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /* Set GPB0 as GPIO output mode(0x01) */ ++ ++ while(count--) ++ { ++ gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /* Set GPB0 as GPIO output mode(0x01) */ ++ ++ gpio->GPBDAT &= ~(1<<BEEP); /* Set Beep GPIO as low level */ ++ delay(DELAY_TIME); ++ ++ gpio->GPBDAT |= 1<<BEEP; /* Set Beep GPIO as high level */ ++ delay(DELAY_TIME); ++ ++ gpio->GPBCON &= ~0x3; /* Set GPB0 as GPIO input mode(0x00) */ ++ } ++ ++ return ; ++} ++#endif ++ ++/* ++ * Miscellaneous platform dependent initialisations ++ */ ++ ++int board_init (void) ++{ ++ struct s3c24x0_clock_power * const clk_power = ++ s3c24x0_get_base_clock_power(); ++ struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio(); ++ ++ /* to reduce PLL lock time, adjust the LOCKTIME register */ ++ clk_power->LOCKTIME = 0xFFFFFF; ++ ++ /* configure MPLL */ ++ clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV); ++ ++ /* some delay between MPLL and UPLL */ ++ delay (4000); ++ ++ /* configure UPLL */ ++ clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV); ++ ++ /* some delay between MPLL and UPLL */ ++ delay (8000); ++ ++ /* set up the I/O ports */ ++ gpio->GPACON = 0x007FFFFF; ++ gpio->GPBCON = 0x00044555; ++ gpio->GPBUP = 0x000007FF; ++ gpio->GPCCON = 0xAAAAAAAA; ++ gpio->GPCUP = 0x0000FFFF; ++ gpio->GPDCON = 0xAAAAAAAA; ++ gpio->GPDUP = 0x0000FFFF; ++ gpio->GPECON = 0xAAAAAAAA; ++ gpio->GPEUP = 0x0000FFFF; ++ gpio->GPFCON = 0x000055AA; ++ gpio->GPFUP = 0x000000FF; ++ gpio->GPGCON = 0xFF95FFBA; ++ gpio->GPGUP = 0x0000FFFF; ++ gpio->GPHCON = 0x002AFAAA; ++ gpio->GPHUP = 0x000007FF; ++ ++ /* arch number of MINI2440-Board */ ++ gd->bd->bi_arch_number = MACH_TYPE_MINI2440; /* Modify by guowenxue */ ++ ++ /* adress of boot parameters */ ++ gd->bd->bi_boot_params = 0x30000100; ++ ++ icache_enable(); ++ dcache_enable(); ++ ++#if defined(CONFIG_FL2440_LED) /* Add by guowenxue, 2012.10.04 */ ++ gpio->GPBDAT = 0x00000181; ++#endif ++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */ ++ turn_beep(); ++#endif ++ ++ return 0; ++} ++ ++int dram_init (void) ++{ ++ gd->bd->bi_dram[0].start = PHYS_SDRAM_1; ++ gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_CMD_NET ++int board_eth_init(bd_t *bis) ++{ ++ int rc = 0; ++#ifdef CONFIG_CS8900 ++ rc = cs8900_initialize(0, CONFIG_CS8900_BASE); ++#endif ++#ifdef CONFIG_DRIVER_DM9000 ++ rc = dm9000_initialize(bis); ++#endif ++ return rc; ++} ++#endif +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/flash.c u-boot-2010.09-fl2440/board/lingyun/fl2440/flash.c +--- u-boot-2010.09/board/lingyun/fl2440/flash.c 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/flash.c 2020-01-09 17:22:17.705412170 +0800 +@@ -0,0 +1,433 @@ ++/* ++ * (C) Copyright 2002 ++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com> ++ * Alex Zuepke <azu@sysgo.de> ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 <common.h> ++ ++ulong myflush (void); ++ ++ ++#define FLASH_BANK_SIZE PHYS_FLASH_SIZE ++#define MAIN_SECT_SIZE 0x10000 /* 64 KB */ ++ ++flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; ++ ++ ++#define CMD_READ_ARRAY 0x000000F0 ++#define CMD_UNLOCK1 0x000000AA ++#define CMD_UNLOCK2 0x00000055 ++#define CMD_ERASE_SETUP 0x00000080 ++#define CMD_ERASE_CONFIRM 0x00000030 ++#define CMD_PROGRAM 0x000000A0 ++#define CMD_UNLOCK_BYPASS 0x00000020 ++ ++#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1))) ++#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1))) ++ ++#define BIT_ERASE_DONE 0x00000080 ++#define BIT_RDY_MASK 0x00000080 ++#define BIT_PROGRAM_ERROR 0x00000020 ++#define BIT_TIMEOUT 0x80000000 /* our flag */ ++ ++#define READY 1 ++#define ERR 2 ++#define TMO 4 ++ ++/*----------------------------------------------------------------------- ++ */ ++ ++ulong flash_init (void) ++{ ++ int i, j; ++ ulong size = 0; ++ ++ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { ++ ulong flashbase = 0; ++ ++ flash_info[i].flash_id = ++#if defined(CONFIG_AMD_LV400) ++ (AMD_MANUFACT & FLASH_VENDMASK) | ++ (AMD_ID_LV400B & FLASH_TYPEMASK); ++#elif defined(CONFIG_AMD_LV800) ++ (AMD_MANUFACT & FLASH_VENDMASK) | ++ (AMD_ID_LV800B & FLASH_TYPEMASK); ++#else ++#error "Unknown flash configured" ++#endif ++ flash_info[i].size = FLASH_BANK_SIZE; ++ flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT; ++ memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT); ++ if (i == 0) ++ flashbase = PHYS_FLASH_1; ++ else ++ panic ("configured too many flash banks!\n"); ++ for (j = 0; j < flash_info[i].sector_count; j++) { ++ if (j <= 3) { ++ /* 1st one is 16 KB */ ++ if (j == 0) { ++ flash_info[i].start[j] = ++ flashbase + 0; ++ } ++ ++ /* 2nd and 3rd are both 8 KB */ ++ if ((j == 1) || (j == 2)) { ++ flash_info[i].start[j] = ++ flashbase + 0x4000 + (j - ++ 1) * ++ 0x2000; ++ } ++ ++ /* 4th 32 KB */ ++ if (j == 3) { ++ flash_info[i].start[j] = ++ flashbase + 0x8000; ++ } ++ } else { ++ flash_info[i].start[j] = ++ flashbase + (j - 3) * MAIN_SECT_SIZE; ++ } ++ } ++ size += flash_info[i].size; ++ } ++ ++ flash_protect (FLAG_PROTECT_SET, ++ CONFIG_SYS_FLASH_BASE, ++ CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1, ++ &flash_info[0]); ++ ++ flash_protect (FLAG_PROTECT_SET, ++ CONFIG_ENV_ADDR, ++ CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]); ++ ++ return size; ++} ++ ++/*----------------------------------------------------------------------- ++ */ ++void flash_print_info (flash_info_t * info) ++{ ++ int i; ++ ++ switch (info->flash_id & FLASH_VENDMASK) { ++ case (AMD_MANUFACT & FLASH_VENDMASK): ++ printf ("AMD: "); ++ break; ++ default: ++ printf ("Unknown Vendor "); ++ break; ++ } ++ ++ switch (info->flash_id & FLASH_TYPEMASK) { ++ case (AMD_ID_LV400B & FLASH_TYPEMASK): ++ printf ("1x Amd29LV400BB (4Mbit)\n"); ++ break; ++ case (AMD_ID_LV800B & FLASH_TYPEMASK): ++ printf ("1x Amd29LV800BB (8Mbit)\n"); ++ break; ++ default: ++ printf ("Unknown Chip Type\n"); ++ goto Done; ++ break; ++ } ++ ++ printf (" Size: %ld MB in %d Sectors\n", ++ info->size >> 20, info->sector_count); ++ ++ printf (" Sector Start Addresses:"); ++ for (i = 0; i < info->sector_count; i++) { ++ if ((i % 5) == 0) { ++ printf ("\n "); ++ } ++ printf (" %08lX%s", info->start[i], ++ info->protect[i] ? " (RO)" : " "); ++ } ++ printf ("\n"); ++ ++ Done:; ++} ++ ++/*----------------------------------------------------------------------- ++ */ ++ ++int flash_erase (flash_info_t * info, int s_first, int s_last) ++{ ++ ushort result; ++ int iflag, cflag, prot, sect; ++ int rc = ERR_OK; ++ int chip; ++ ++ /* first look for protection bits */ ++ ++ if (info->flash_id == FLASH_UNKNOWN) ++ return ERR_UNKNOWN_FLASH_TYPE; ++ ++ if ((s_first < 0) || (s_first > s_last)) { ++ return ERR_INVAL; ++ } ++ ++ if ((info->flash_id & FLASH_VENDMASK) != ++ (AMD_MANUFACT & FLASH_VENDMASK)) { ++ return ERR_UNKNOWN_FLASH_VENDOR; ++ } ++ ++ prot = 0; ++ for (sect = s_first; sect <= s_last; ++sect) { ++ if (info->protect[sect]) { ++ prot++; ++ } ++ } ++ if (prot) ++ return ERR_PROTECTED; ++ ++ /* ++ * Disable interrupts which might cause a timeout ++ * here. Remember that our exception vectors are ++ * at address 0 in the flash, and we don't want a ++ * (ticker) exception to happen while the flash ++ * chip is in programming mode. ++ */ ++ cflag = icache_status (); ++ icache_disable (); ++ iflag = disable_interrupts (); ++ ++ /* Start erase on unprotected sectors */ ++ for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { ++ printf ("Erasing sector %2d ... ", sect); ++ ++ /* arm simple, non interrupt dependent timer */ ++ reset_timer_masked (); ++ ++ if (info->protect[sect] == 0) { /* not protected */ ++ vu_short *addr = (vu_short *) (info->start[sect]); ++ ++ MEM_FLASH_ADDR1 = CMD_UNLOCK1; ++ MEM_FLASH_ADDR2 = CMD_UNLOCK2; ++ MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; ++ ++ MEM_FLASH_ADDR1 = CMD_UNLOCK1; ++ MEM_FLASH_ADDR2 = CMD_UNLOCK2; ++ *addr = CMD_ERASE_CONFIRM; ++ ++ /* wait until flash is ready */ ++ chip = 0; ++ ++ do { ++ result = *addr; ++ ++ /* check timeout */ ++ if (get_timer_masked () > ++ CONFIG_SYS_FLASH_ERASE_TOUT) { ++ MEM_FLASH_ADDR1 = CMD_READ_ARRAY; ++ chip = TMO; ++ break; ++ } ++ ++ if (!chip ++ && (result & 0xFFFF) & BIT_ERASE_DONE) ++ chip = READY; ++ ++ if (!chip ++ && (result & 0xFFFF) & BIT_PROGRAM_ERROR) ++ chip = ERR; ++ ++ } while (!chip); ++ ++ MEM_FLASH_ADDR1 = CMD_READ_ARRAY; ++ ++ if (chip == ERR) { ++ rc = ERR_PROG_ERROR; ++ goto outahere; ++ } ++ if (chip == TMO) { ++ rc = ERR_TIMOUT; ++ goto outahere; ++ } ++ ++ printf ("ok.\n"); ++ } else { /* it was protected */ ++ ++ printf ("protected!\n"); ++ } ++ } ++ ++ if (ctrlc ()) ++ printf ("User Interrupt!\n"); ++ ++ outahere: ++ /* allow flash to settle - wait 10 ms */ ++ udelay_masked (10000); ++ ++ if (iflag) ++ enable_interrupts (); ++ ++ if (cflag) ++ icache_enable (); ++ ++ return rc; ++} ++ ++/*----------------------------------------------------------------------- ++ * Copy memory to flash ++ */ ++ ++static int write_hword (flash_info_t * info, ulong dest, ushort data) ++{ ++ vu_short *addr = (vu_short *) dest; ++ ushort result; ++ int rc = ERR_OK; ++ int cflag, iflag; ++ int chip; ++ ++ /* ++ * Check if Flash is (sufficiently) erased ++ */ ++ result = *addr; ++ if ((result & data) != data) ++ return ERR_NOT_ERASED; ++ ++ ++ /* ++ * Disable interrupts which might cause a timeout ++ * here. Remember that our exception vectors are ++ * at address 0 in the flash, and we don't want a ++ * (ticker) exception to happen while the flash ++ * chip is in programming mode. ++ */ ++ cflag = icache_status (); ++ icache_disable (); ++ iflag = disable_interrupts (); ++ ++ MEM_FLASH_ADDR1 = CMD_UNLOCK1; ++ MEM_FLASH_ADDR2 = CMD_UNLOCK2; ++ MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS; ++ *addr = CMD_PROGRAM; ++ *addr = data; ++ ++ /* arm simple, non interrupt dependent timer */ ++ reset_timer_masked (); ++ ++ /* wait until flash is ready */ ++ chip = 0; ++ do { ++ result = *addr; ++ ++ /* check timeout */ ++ if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) { ++ chip = ERR | TMO; ++ break; ++ } ++ if (!chip && ((result & 0x80) == (data & 0x80))) ++ chip = READY; ++ ++ if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) { ++ result = *addr; ++ ++ if ((result & 0x80) == (data & 0x80)) ++ chip = READY; ++ else ++ chip = ERR; ++ } ++ ++ } while (!chip); ++ ++ *addr = CMD_READ_ARRAY; ++ ++ if (chip == ERR || *addr != data) ++ rc = ERR_PROG_ERROR; ++ ++ if (iflag) ++ enable_interrupts (); ++ ++ if (cflag) ++ icache_enable (); ++ ++ return rc; ++} ++ ++/*----------------------------------------------------------------------- ++ * Copy memory to flash. ++ */ ++ ++int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) ++{ ++ ulong cp, wp; ++ int l; ++ int i, rc; ++ ushort data; ++ ++ wp = (addr & ~1); /* get lower word aligned address */ ++ ++ /* ++ * handle unaligned start bytes ++ */ ++ if ((l = addr - wp) != 0) { ++ data = 0; ++ for (i = 0, cp = wp; i < l; ++i, ++cp) { ++ data = (data >> 8) | (*(uchar *) cp << 8); ++ } ++ for (; i < 2 && cnt > 0; ++i) { ++ data = (data >> 8) | (*src++ << 8); ++ --cnt; ++ ++cp; ++ } ++ for (; cnt == 0 && i < 2; ++i, ++cp) { ++ data = (data >> 8) | (*(uchar *) cp << 8); ++ } ++ ++ if ((rc = write_hword (info, wp, data)) != 0) { ++ return (rc); ++ } ++ wp += 2; ++ } ++ ++ /* ++ * handle word aligned part ++ */ ++ while (cnt >= 2) { ++ data = *((vu_short *) src); ++ if ((rc = write_hword (info, wp, data)) != 0) { ++ return (rc); ++ } ++ src += 2; ++ wp += 2; ++ cnt -= 2; ++ } ++ ++ if (cnt == 0) { ++ return ERR_OK; ++ } ++ ++ /* ++ * handle unaligned tail bytes ++ */ ++ data = 0; ++ for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) { ++ data = (data >> 8) | (*src++ << 8); ++ --cnt; ++ } ++ for (; i < 2; ++i, ++cp) { ++ data = (data >> 8) | (*(uchar *) cp << 8); ++ } ++ ++ return write_hword (info, wp, data); ++} +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S u-boot-2010.09-fl2440/board/lingyun/fl2440/lowlevel_init.S +--- u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/lowlevel_init.S 2020-01-09 17:22:17.705412170 +0800 +@@ -0,0 +1,198 @@ ++/* ++ * Memory Setup stuff - taken from blob memsetup.S ++ * ++ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and ++ * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) ++ * ++ * Modified for the Samsung SMDK2410 by ++ * (C) Copyright 2002 ++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 <config.h> ++#include <version.h> ++ ++ ++/* some parameters for the board */ ++ ++/* ++ * ++ * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S ++ * ++ * Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com> ++ * ++ */ ++ ++#define BWSCON 0x48000000 ++#define GPBCON 0x56000010 ++#define GPBDAT 0x56000014 ++#define GPBUP 0x56000018 ++ ++/* BWSCON */ ++#define DW8 (0x0) ++#define DW16 (0x1) ++#define DW32 (0x2) ++#define WAIT (0x1<<2) ++#define UBLB (0x1<<3) ++ ++#define B1_BWSCON (DW32) ++#define B2_BWSCON (DW16) ++#define B3_BWSCON (DW16 + WAIT + UBLB) ++#define B4_BWSCON (DW16) ++#define B5_BWSCON (DW16) ++#define B6_BWSCON (DW32) ++#define B7_BWSCON (DW32) ++ ++/* BANK0CON */ ++#define B0_Tacs 0x0 /* 0clk */ ++#define B0_Tcos 0x0 /* 0clk */ ++#define B0_Tacc 0x7 /* 14clk */ ++#define B0_Tcoh 0x0 /* 0clk */ ++#define B0_Tah 0x0 /* 0clk */ ++#define B0_Tacp 0x0 ++#define B0_PMC 0x0 /* normal */ ++ ++/* BANK1CON */ ++#define B1_Tacs 0x0 /* 0clk */ ++#define B1_Tcos 0x0 /* 0clk */ ++#define B1_Tacc 0x7 /* 14clk */ ++#define B1_Tcoh 0x0 /* 0clk */ ++#define B1_Tah 0x0 /* 0clk */ ++#define B1_Tacp 0x0 ++#define B1_PMC 0x0 ++ ++#define B2_Tacs 0x0 ++#define B2_Tcos 0x0 ++#define B2_Tacc 0x7 ++#define B2_Tcoh 0x0 ++#define B2_Tah 0x0 ++#define B2_Tacp 0x0 ++#define B2_PMC 0x0 ++ ++#define B3_Tacs 0x0 /* 0clk */ ++#define B3_Tcos 0x3 /* 4clk */ ++#define B3_Tacc 0x7 /* 14clk */ ++#define B3_Tcoh 0x1 /* 1clk */ ++#define B3_Tah 0x0 /* 0clk */ ++#define B3_Tacp 0x3 /* 6clk */ ++#define B3_PMC 0x0 /* normal */ ++ ++#define B4_Tacs 0x0 /* 0clk */ ++#define B4_Tcos 0x0 /* 0clk */ ++#define B4_Tacc 0x7 /* 14clk */ ++#define B4_Tcoh 0x0 /* 0clk */ ++#define B4_Tah 0x0 /* 0clk */ ++#define B4_Tacp 0x0 ++#define B4_PMC 0x0 /* normal */ ++ ++#define B5_Tacs 0x0 /* 0clk */ ++#define B5_Tcos 0x0 /* 0clk */ ++#define B5_Tacc 0x7 /* 14clk */ ++#define B5_Tcoh 0x0 /* 0clk */ ++#define B5_Tah 0x0 /* 0clk */ ++#define B5_Tacp 0x0 ++#define B5_PMC 0x0 /* normal */ ++ ++/* SDRAM is on HSB bus, so its clock is from HCLK, FCLK=400, HCLK=100; so SDRAM 1clk=10ns */ ++ ++#define B6_MT 0x3 /* SDRAM */ ++// K4S561632 datasheet: RAS to CAS delay(Trcd) Min value should be 18/20ns, HCLK is 100MHz, so 1clk=10ns ++// EM63A165 datasheet: RAS# to CAS# delay(Trcd) Min value should be 15/20ns, HCLK is 100MHz, so 1clk=10ns ++#define B6_Trcd 0x2 /* 4clk */ ++#define B6_SCAN 0x1 /* 9bit */ ++ ++#define B7_MT 0x3 /* SDRAM */ ++#define B7_Trcd 0x1 /* 3clk */ ++#define B7_SCAN 0x1 /* 9bit */ ++ ++/* REFRESH register<0x48000024> parameter */ ++#define REFEN 0x1 /* Refresh enable */ ++#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ ++ ++// Trp: Row precharge time ++// K4S561632 datasheet: Min(Trp) value should be 18/20ns; ++// EM63A165 datasheet: Min value should be 15/20ns; ++#define Trp 0x2 /* 4clk */ ++ ++// Trc: Row cycle time ++// K4S561632 datasheet: Min value should be 60/65ns; ++// EM63A165 datasheet: Min value should be 60/63ns; ++// S3C2440 datasheet: REFRESH register describe: SDRAM Row cycle time: Trc=Tsrc+Trp ++#define Tsrc 0x2 /* 6clk, so Trc=Tsrc+Trp=6+3=9clk */ ++ ++// K4S561632 datasheet: 64ms refresh period (8K Cycle): 64000/8192=7.81us ++// EM63A165 datasheet: 8192 refresh cycles/64ms: 64000/8192=7.81us ++// S3C2440 datasheet: REFRESH Register Refresh period = (2^11-refresh_count+1)/HCLK ++// So Refresh count = 2^11 + 1 - 100x7.81 = 1268 ++#define REFCNT 1268 ++//#define REFCNT 489 /* HCLK=100Mhz, (2048+1-15.6*100) */ ++ ++ ++/**************************************/ ++ ++_TEXT_BASE: ++ .word TEXT_BASE ++ ++.globl lowlevel_init ++lowlevel_init: ++ ldr r5, =GPBDAT ++ ldr r6, [r5] ++ bic r6, r6, #(1<<8) ++ str r6, [r5] ++ ++ /* memory control configuration */ ++ /* make r0 relative the current location so that it */ ++ /* reads SMRDATA out of FLASH rather than memory ! */ ++ ldr r0, =SMRDATA ++ ldr r1, =lowlevel_init ++ sub r0, r0, r1 ++ adr r3, lowlevel_init /* r3 <- current position of code */ ++ add r0, r0, r3 ++ ldr r1, =BWSCON /* Bus Width Status Controller */ ++ add r2, r0, #13*4 ++ ++0: ++ ldr r3, [r0], #4 ++ str r3, [r1], #4 ++ cmp r2, r0 ++ bne 0b ++ ++ /* everything is fine now */ ++ mov pc, lr ++ ++ .ltorg ++/* the literal pools origin */ ++ ++SMRDATA: ++ .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) ++ .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ++ .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ++ .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ++ .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ++ .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ++ .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ++ .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ++ .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ++ .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+REFCNT) ++ .word 0xb2 ++ .word 0x30 ++ .word 0x30 +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/Makefile u-boot-2010.09-fl2440/board/lingyun/fl2440/Makefile +--- u-boot-2010.09/board/lingyun/fl2440/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/Makefile 2020-01-09 17:22:17.705412170 +0800 +@@ -0,0 +1,51 @@ ++# ++# (C) Copyright 2000-2006 ++# Wolfgang Denk, DENX Software Engineering, wd@denx.de. ++# ++# See file CREDITS for list of people who contributed to this ++# project. ++# ++# 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 $(TOPDIR)/config.mk ++ ++LIB = $(obj)lib$(BOARD).a ++ ++COBJS := fl2440.o nand_read.o ++SOBJS := lowlevel_init.o ++ ++SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) ++OBJS := $(addprefix $(obj),$(COBJS)) ++SOBJS := $(addprefix $(obj),$(SOBJS)) ++ ++$(LIB): $(obj).depend $(OBJS) $(SOBJS) ++ $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) ++ ++clean: ++ rm -f $(SOBJS) $(OBJS) ++ ++distclean: clean ++ rm -f $(LIB) core *.bak $(obj).depend ++ ++######################################################################### ++ ++# defines $(obj).depend target ++include $(SRCTREE)/rules.mk ++ ++sinclude $(obj).depend ++ ++######################################################################### +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/nand_read.c u-boot-2010.09-fl2440/board/lingyun/fl2440/nand_read.c +--- u-boot-2010.09/board/lingyun/fl2440/nand_read.c 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/board/lingyun/fl2440/nand_read.c 2020-01-09 17:22:17.705412170 +0800 +@@ -0,0 +1,212 @@ ++/* ++ * nand_read.c: Simple NAND read functions for booting from NAND ++ * ++ * This is used by cpu/arm920/start.S assembler code, ++ * and the board-specific linker script must make sure this ++ * file is linked within the first 4kB of NAND flash. ++ * ++ * Taken from GPLv2 licensed vivi bootloader, ++ * Copyright (C) 2002 MIZI Research, Inc. ++ * ++ * Author: Hwang, Chideok <hwang@mizi.com> ++ * Date : $Date: 2004/02/04 10:37:37 $ ++ * ++ * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. ++ * Author: Harald Welte <laforge@openmoko.org> ++ */ ++ ++#include <common.h> ++#include <linux/mtd/nand.h> ++ ++ ++#define __REGb(x) (*(volatile unsigned char *)(x)) ++#define __REGw(x) (*(volatile unsigned short *)(x)) ++#define __REGi(x) (*(volatile unsigned int *)(x)) ++#define NF_BASE 0x4e000000 ++#if defined(CONFIG_S3C2410) ++#define NFCONF __REGi(NF_BASE + 0x0) ++#define NFCMD __REGb(NF_BASE + 0x4) ++#define NFADDR __REGb(NF_BASE + 0x8) ++#define NFDATA __REGb(NF_BASE + 0xc) ++#define NFSTAT __REGb(NF_BASE + 0x10) ++#define NFSTAT_BUSY 1 ++#define nand_select() (NFCONF &= ~0x800) ++#define nand_deselect() (NFCONF |= 0x800) ++#define nand_clear_RnB() do {} while (0) ++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) ++#define NFCONF __REGi(NF_BASE + 0x0) ++#define NFCONT __REGi(NF_BASE + 0x4) ++#define NFCMD __REGb(NF_BASE + 0x8) ++#define NFADDR __REGb(NF_BASE + 0xc) ++#define NFDATA __REGb(NF_BASE + 0x10) ++#define NFDATA16 __REGw(NF_BASE + 0x10) ++#define NFSTAT __REGb(NF_BASE + 0x20) ++#define NFSTAT_BUSY 1 ++#define nand_select() (NFCONT &= ~(1 << 1)) ++#define nand_deselect() (NFCONT |= (1 << 1)) ++#define nand_clear_RnB() (NFSTAT |= (1 << 2)) ++#endif ++ ++static inline void nand_wait(void) ++{ ++ int i; ++ ++ while (!(NFSTAT & NFSTAT_BUSY)) ++ for (i=0; i<10; i++); ++} ++ ++struct boot_nand_t { ++ int page_size; ++ int block_size; ++ int bad_block_offset; ++}; ++ ++static int is_bad_block(struct boot_nand_t * nand, unsigned long i) ++{ ++ unsigned char data; ++ unsigned long page_num; ++ ++ nand_clear_RnB(); ++ if (nand->page_size == 512) { ++ NFCMD = NAND_CMD_READOOB; /* 0x50 */ ++ NFADDR = nand->bad_block_offset & 0xf; ++ NFADDR = (i >> 9) & 0xff; ++ NFADDR = (i >> 17) & 0xff; ++ NFADDR = (i >> 25) & 0xff; ++ } else if (nand->page_size == 2048) { ++ page_num = i >> 11; /* addr / 2048 */ ++ NFCMD = NAND_CMD_READ0; ++ NFADDR = nand->bad_block_offset & 0xff; ++ NFADDR = (nand->bad_block_offset >> 8) & 0xff; ++ NFADDR = page_num & 0xff; ++ NFADDR = (page_num >> 8) & 0xff; ++ NFADDR = (page_num >> 16) & 0xff; ++ NFCMD = NAND_CMD_READSTART; ++ } else { ++ return -1; ++ } ++ nand_wait(); ++ data = (NFDATA & 0xff); ++ if (data != 0xff) ++ return 1; ++ ++ return 0; ++} ++ ++static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr) ++{ ++ unsigned short *ptr16 = (unsigned short *)buf; ++ unsigned int i, page_num; ++ ++ nand_clear_RnB(); ++ ++ NFCMD = NAND_CMD_READ0; ++ ++ if (nand->page_size == 512) { ++ /* Write Address */ ++ NFADDR = addr & 0xff; ++ NFADDR = (addr >> 9) & 0xff; ++ NFADDR = (addr >> 17) & 0xff; ++ NFADDR = (addr >> 25) & 0xff; ++ } else if (nand->page_size == 2048) { ++ page_num = addr >> 11; /* addr / 2048 */ ++ /* Write Address */ ++ NFADDR = 0; ++ NFADDR = 0; ++ NFADDR = page_num & 0xff; ++ NFADDR = (page_num >> 8) & 0xff; ++ NFADDR = (page_num >> 16) & 0xff; ++ NFCMD = NAND_CMD_READSTART; ++ } else { ++ return -1; ++ } ++ nand_wait(); ++ ++#if defined(CONFIG_S3C2410) ++ for (i = 0; i < nand->page_size; i++) { ++ *buf = (NFDATA & 0xff); ++ buf++; ++ } ++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) ++ for (i = 0; i < (nand->page_size>>1); i++) { ++ *ptr16 = NFDATA16; ++ ptr16++; ++ } ++#endif ++ ++ return nand->page_size; ++} ++ ++static unsigned short nand_read_id() ++{ ++ unsigned short res = 0; ++ NFCMD = NAND_CMD_READID; ++ NFADDR = 0; ++ res = NFDATA; ++ res = (res << 8) | NFDATA; ++ return res; ++} ++ ++extern unsigned int dynpart_size[]; ++ ++/* low level nand read function */ ++int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) ++{ ++ int i, j; ++ unsigned short nand_id; ++ struct boot_nand_t nand; ++ ++ /* chip Enable */ ++ nand_select(); ++ nand_clear_RnB(); ++ ++ for (i = 0; i < 10; i++) ++ ; ++ nand_id = nand_read_id(); ++ if (0) { /* dirty little hack to detect if nand id is misread */ ++ unsigned short * nid = (unsigned short *)0x31fffff0; ++ *nid = nand_id; ++ } ++ ++ if (nand_id == 0xec76 || /* Samsung K91208 on SD2410 board */ ++ nand_id == 0xad76 ) { /*Hynix HY27US08121A*/ ++ nand.page_size = 512; ++ nand.block_size = 16 * 1024; ++ nand.bad_block_offset = 5; ++ // nand.size = 0x4000000; ++ } else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */ ++ nand_id == 0xadda || /* Hynix HY27UF082G2B on FL2440 board */ ++ nand_id == 0xecda || /* Samsung K9F2G08U0B on FL2440 board */ ++ nand_id == 0xecd3 ) { /* Samsung K9K8G08 */ ++ nand.page_size = 2048; ++ nand.block_size = 128 * 1024; ++ nand.bad_block_offset = nand.page_size; ++ // nand.size = 0x8000000; ++ } else { ++ return -1; // hang ++ } ++ if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1)))) ++ return -1; /* invalid alignment */ ++ ++ for (i=start_addr; i < (start_addr + size);) { ++#ifdef CONFIG_S3C2410_NAND_SKIP_BAD ++ if (i & (nand.block_size-1)== 0) { ++ if (is_bad_block(&nand, i) || ++ is_bad_block(&nand, i + nand.page_size)) { ++ /* Bad block */ ++ i += nand.block_size; ++ size += nand.block_size; ++ continue; ++ } ++ } ++#endif ++ j = nand_read_page_ll(&nand, buf, i); ++ i += j; ++ buf += j; ++ } ++ ++ /* chip Disable */ ++ nand_deselect(); ++ ++ return 0; ++} +diff -Nuar u-boot-2010.09/boards.cfg u-boot-2010.09-fl2440/boards.cfg +--- u-boot-2010.09/boards.cfg 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/boards.cfg 2020-01-09 17:22:17.709412170 +0800 +@@ -238,6 +238,7 @@ + sbc2410x arm arm920t - - s3c24x0 + smdk2400 arm arm920t - samsung s3c24x0 + smdk2410 arm arm920t - samsung s3c24x0 ++fl2440 arm arm920t fl2440 lingyun s3c24x0 + voiceblue arm arm925t + omap1510inn arm arm925t - ti + afeb9260 arm arm926ejs - - at91 +diff -Nuar u-boot-2010.09/build.sh u-boot-2010.09-fl2440/build.sh +--- u-boot-2010.09/build.sh 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/build.sh 2020-01-09 17:25:25.785415778 +0800 +@@ -0,0 +1,72 @@ ++#!/bin/bash ++ ++BOARD=fl2440 ++TFTP_PATH=/tftp ++IMGS_PATH=../images ++IMG_NAME=u-boot-${BOARD}.bin ++ ++CROSSTOOL=/opt/buildroot/cortex-a5/bin/arm-linux- ++JOBS=`cat /proc/cpuinfo |grep "processor"|wc -l` ++ ++ ++function do_clean() ++{ ++ make CROSS_COMPILE=${CROSSTOOL} distclean ++ rm -f tools/logos/logo.bmp ++ rm -f cscope* tags ++ rm -f ${IMG_NAME} ++} ++ ++function do_modify() ++{ ++ grep "arm-linux-gnueabi" Makefile > /dev/null ++ ++ if [ $? == 0 ] ; then ++ return ; ++ fi ++ ++ echo "Modify Makefile for ARCH and cross compiler" ++ sed -i -e "s|^CROSS_COMPILE=.*|CROSS_COMPILE=${CROSSTOOL}|g" Makefile ++} ++ ++function do_build() ++{ ++ make fl2440_config ++ ++ make -j${JOBS} ++ ++ if [ ! -f ${IMG_NAME} ] ; then ++ mv u-boot-*.bin ${IMG_NAME} ++ fi ++ ++ chmod a+x ${IMG_NAME} ++} ++ ++function do_install() ++{ ++ if [ -w $TFTP_PATH ] ;then ++ echo "cp ${IMG_NAME} $TFTP_PATH" ++ cp ${IMG_NAME} $TFTP_PATH ++ fi ++ ++ if [ -w ${IMGS_PATH} ] ; then ++ echo "cp ${IMG_NAME} $IMGS_PATH" ++ cp ${IMG_NAME} $IMGS_PATH ++ fi ++} ++ ++if [ "$1" == "clean" ] ; then ++ ++ do_clean ++ exit 0; ++fi ++ ++do_modify ++ ++set -e ++ ++do_build ++ ++do_install ++ ++ +diff -Nuar u-boot-2010.09/common/cmd_nand.c u-boot-2010.09-fl2440/common/cmd_nand.c +--- u-boot-2010.09/common/cmd_nand.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/common/cmd_nand.c 2020-01-09 17:22:17.709412170 +0800 +@@ -148,6 +148,11 @@ + #if defined(CONFIG_CMD_MTDPARTS) + out: + #endif ++ /* If the size is not aligment, then let it's page alignment */ ++ if(0 != (*size%nand->writesize)) ++ { ++ *size = (*size / nand->writesize + 1) * nand->writesize; ++ } + printf("device %d ", idx); + if (*size == nand->size) + puts("whole chip\n"); +diff -Nuar u-boot-2010.09/common/env_common.c u-boot-2010.09-fl2440/common/env_common.c +--- u-boot-2010.09/common/env_common.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/common/env_common.c 2020-01-09 17:22:17.709412170 +0800 +@@ -57,7 +57,34 @@ + "bootargs=" CONFIG_BOOTARGS "\0" + #endif + #ifdef CONFIG_BOOTCOMMAND +- "bootcmd=" CONFIG_BOOTCOMMAND "\0" ++ "bootcmd=" CONFIG_BOOTCOMMAND "\0" ++#endif ++#ifdef CONFIG_BBL_COMMAND /* Add by guowenxue, burn u-boot image */ ++ "bbl=" CONFIG_BBL_COMMAND "\0" ++#endif ++#ifdef CONFIG_BLX_COMMAND /* Add by guowenxue, burn linux kernel image */ ++ "blx=" CONFIG_BLX_COMMAND "\0" ++#endif ++#ifdef CONFIG_BURN_UBIFS /* Add by guowenxue, burn UBIFS root filesystem image */ ++ "bubifs=" CONFIG_BURN_UBIFS "\0" ++#endif ++#ifdef CONFIG_BURN_JFFS2 /* Add by guowenxue, burn JFFS2 root filesystem image */ ++ "bjffs2=" CONFIG_BURN_JFFS2 "\0" ++#endif ++#ifdef CONFIG_BSYS_COMMAND /* Add by guowenxue, burn linux kernel and rootfs */ ++ "bsys=" CONFIG_BSYS_COMMAND "\0" ++#endif ++#ifdef CONFIG_BARGS_INITRAMFS /* Add by guowenxue, bootargs for initramfs rootfs */ ++ "args_initramfs=" CONFIG_BARGS_INITRAMFS "\0" ++#endif ++#ifdef CONFIG_BARGS_UBIFS /* Add by guowenxue, bootargs for ubifs rootfs */ ++ "args_ubifs=" CONFIG_BARGS_UBIFS "\0" ++#endif ++#ifdef CONFIG_BARGS_JFFS2 /* Add by guowenxue, bootargs for jffs2 rootfs */ ++ "args_jffs2=" CONFIG_BARGS_JFFS2 "\0" ++#endif ++#ifdef CONFIG_TFTPBOOT_COMMAND /* Add by guowenxue, tftp boot linux system */ ++ "tb=" CONFIG_TFTPBOOT_COMMAND "\0" + #endif + #ifdef CONFIG_RAMBOOTCOMMAND + "ramboot=" CONFIG_RAMBOOTCOMMAND "\0" +diff -Nuar u-boot-2010.09/common/serial.c u-boot-2010.09-fl2440/common/serial.c +--- u-boot-2010.09/common/serial.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/common/serial.c 2020-01-09 17:22:17.709412170 +0800 +@@ -68,7 +68,7 @@ + #else + #error "Bad CONFIG_PSC_CONSOLE." + #endif +-#elif defined(CONFIG_S3C2410) ++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + #if defined(CONFIG_SERIAL1) + return &s3c24xx_serial0_device; + #elif defined(CONFIG_SERIAL2) +@@ -157,7 +157,7 @@ + #if defined (CONFIG_STUART) + serial_register(&serial_stuart_device); + #endif +-#if defined(CONFIG_S3C2410) ++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + serial_register(&s3c24xx_serial0_device); + serial_register(&s3c24xx_serial1_device); + serial_register(&s3c24xx_serial2_device); +diff -Nuar u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c u-boot-2010.09-fl2440/drivers/mtd/nand/s3c2410_nand.c +--- u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/drivers/mtd/nand/s3c2410_nand.c 2020-01-09 17:22:17.709412170 +0800 +@@ -24,6 +24,7 @@ + #include <asm/arch/s3c24x0_cpu.h> + #include <asm/io.h> + ++#if defined(CONFIG_S3C2410) + #define S3C2410_NFCONF_EN (1<<15) + #define S3C2410_NFCONF_512BYTE (1<<14) + #define S3C2410_NFCONF_4STEP (1<<13) +@@ -36,6 +37,20 @@ + #define S3C2410_ADDR_NALE 4 + #define S3C2410_ADDR_NCLE 8 + ++#elif defined(CONFIG_S3C2440) ++#define S3C2410_NFCONT_EN (1<<0) ++#define S3C2410_NFCONT_INITECC (1<<4) ++#define S3C2410_NFCONT_nFCE (1<<1) ++#define S3C2410_NFCONT_MAINECCLOCK (1<<5) ++#define S3C2410_NFCONF_TACLS(x) ((x)<<12) ++#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8) ++#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4) ++ ++#define S3C2410_ADDR_NALE 0x08 ++#define S3C2410_ADDR_NCLE 0x0c ++#endif ++ulong IO_ADDR_W = CONFIG_SYS_NAND_BASE; ++ + #ifdef CONFIG_NAND_SPL + + /* in the early stage of NAND flash booting, printf() is not available */ +@@ -59,25 +74,31 @@ + debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl); + + if (ctrl & NAND_CTRL_CHANGE) { +- ulong IO_ADDR_W = (ulong)nand; ++ IO_ADDR_W = (ulong)nand; + + if (!(ctrl & NAND_CLE)) + IO_ADDR_W |= S3C2410_ADDR_NCLE; + if (!(ctrl & NAND_ALE)) + IO_ADDR_W |= S3C2410_ADDR_NALE; + +- chip->IO_ADDR_W = (void *)IO_ADDR_W; ++ //chip->IO_ADDR_W = (void *)IO_ADDR_W; + + if (ctrl & NAND_NCE) +- writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, +- &nand->NFCONF); ++#if defined(CONFIG_S3C2410) ++ writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, &nand->NFCONF); ++#elif defined(CONFIG_S3C2440) ++ writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE, &nand->NFCONT); ++#endif + else +- writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, +- &nand->NFCONF); ++#if defined(CONFIG_S3C2410) ++ writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, &nand->NFCONF); ++#elif defined(CONFIG_S3C2440) ++ writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE, &nand->NFCONT); ++#endif + } + + if (cmd != NAND_CMD_NONE) +- writeb(cmd, chip->IO_ADDR_W); ++ writeb(cmd, (void *)IO_ADDR_W); + } + + static int s3c2410_dev_ready(struct mtd_info *mtd) +@@ -92,7 +113,11 @@ + { + struct s3c2410_nand *nand = s3c2410_get_base_nand(); + debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode); ++#if defined(CONFIG_S3C2410) + writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF); ++#elif defined(CONFIG_S3C2440) ++ writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT); ++#endif + } + + static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, +@@ -132,6 +157,7 @@ + + writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON); + ++#if defined(CONFIG_S3C2410) + /* initialize hardware */ + twrph0 = 3; + twrph1 = 0; +@@ -145,6 +171,20 @@ + + /* initialize nand_chip data structure */ + nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; ++#elif defined(CONFIG_S3C2440) ++ twrph0 = 4; ++ twrph1 = 2; ++ tacls = 0; ++ cfg = 0; ++ cfg |= S3C2410_NFCONF_TACLS(tacls - 1); ++ cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); ++ cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); ++ writel(cfg, &nand_reg->NFCONF); ++ cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0); ++ writel(cfg, &nand_reg->NFCONT); ++ /* initialize nand_chip data structure */ ++ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; ++#endif + + nand->select_chip = NULL; + +diff -Nuar u-boot-2010.09/drivers/net/dm9000x.c u-boot-2010.09-fl2440/drivers/net/dm9000x.c +--- u-boot-2010.09/drivers/net/dm9000x.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/drivers/net/dm9000x.c 2020-01-09 17:22:17.709412170 +0800 +@@ -364,7 +364,7 @@ + while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */ + udelay(1000); + i++; +- if (i == 10000) { ++ if (i == 2000) { /* Modify by guowenxue */ + printf("could not establish link\n"); + return 0; + } +diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-fl2440/include/configs/fl2440.h +--- u-boot-2010.09/include/configs/fl2440.h 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-fl2440/include/configs/fl2440.h 2020-01-09 17:22:17.709412170 +0800 +@@ -0,0 +1,239 @@ ++/* ++ * (C) Copyright 2002 ++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com> ++ * Marius Groeger <mgroeger@sysgo.de> ++ * Gary Jennejohn <garyj@denx.de> ++ * David Mueller <d.mueller@elsoft.ch> ++ * ++ * Configuation settings for the SAMSUNG SMDK2410 board. ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 ++ */ ++ ++#ifndef __CONFIG_H ++#define __CONFIG_H ++ ++/* ++ * High Level Configuration Options ++ * (easy to change) ++ */ ++#define CONFIG_ARM920T 1 /* This is an ARM920T Core */ ++#define CONFIG_S3C24X0 1 /* in a SAMSUNG S3C24x0-type SoC */ ++#define CONFIG_S3C2440 1 /* specifically a SAMSUNG S3C2440 SoC */ ++#define CONFIG_FL2440 1 /* FL2440 board */ ++ ++#define CONFIG_FL2440_LED 1 ++#define CONFIG_FL2440_BEEP 1 ++#define CONFIG_S3C2410_NAND_SKIP_BAD 1 ++ ++/* input clock of PLL */ ++#define CONFIG_SYS_CLK_FREQ 12000000/* the SMDK2410 has 12MHz input clock */ ++ ++ ++#define USE_920T_MMU 1 ++#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */ ++ ++/* ++ * Size of malloc() pool ++ */ ++#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 128*1024) ++#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ ++ ++/* ++ * Hardware drivers ++ */ ++#define CONFIG_NET_MULTI 1 ++#define CONFIG_NET_RETRY_COUNT 20 ++#define CONFIG_DRIVER_DM9000 1 ++#define CONFIG_DM9000_BASE 0x20000300 /* nGCS4 */ ++#define DM9000_IO CONFIG_DM9000_BASE ++#define DM9000_DATA (CONFIG_DM9000_BASE+4) ++#define CONFIG_DM9000_USE_16BIT 1 ++#define CONFIG_DM9000_NO_SROM 1 ++#undef CONFIG_DM9000_DEBUG ++ ++/* ++ * select serial console configuration ++ */ ++#define CONFIG_S3C24X0_SERIAL ++#define CONFIG_SERIAL1 1 /* we use SERIAL 1 on SMDK2410 */ ++ ++/************************************************************ ++ * RTC ++ ************************************************************/ ++#define CONFIG_RTC_S3C24X0 1 ++ ++/* allow to overwrite serial and ethaddr */ ++#define CONFIG_ENV_OVERWRITE ++ ++#define CONFIG_BAUDRATE 115200 ++ ++ ++/* ++ * BOOTP options ++ */ ++#define CONFIG_BOOTP_BOOTFILESIZE ++#define CONFIG_BOOTP_BOOTPATH ++#define CONFIG_BOOTP_GATEWAY ++#define CONFIG_BOOTP_HOSTNAME ++ ++ ++/* ++ * Command line configuration. ++ */ ++#include <config_cmd_default.h> ++ ++#define CONFIG_CMD_CACHE ++#define CONFIG_CMD_DATE ++#define CONFIG_CMD_ELF ++#define CONFIG_CMD_PING ++#define CONFIG_CMD_NAND ++ ++ ++#define CONFIG_BOOTDELAY 2 ++#define CONFIG_ETHADDR 08:00:3e:26:0a:5b ++#define CONFIG_NETMASK 255.255.255.0 ++#define CONFIG_IPADDR 192.168.2.168 ++#define CONFIG_SERVERIP 192.168.2.8 ++ ++ ++#define CONFIG_BBL_COMMAND "tftp 30008000 u-boot-fl2440.bin;nand erase 0 100000;nand write 30008000 0 60000" ++#define CONFIG_BLX_COMMAND "tftp 30008000 linuxrom-fl2440.bin;nand erase 100000 F00000;nand write 30008000 100000 D00000" ++#define CONFIG_BSYS_COMMAND "run blx;run bubifs" ++#define CONFIG_TFTPBOOT_COMMAND "tftp 30008000 linuxrom-fl2440.bin; bootm 30008000" ++#define CONFIG_BURN_JFFS2 "tftp 30008000 rootfs-fl2440.jfs;nand erase 1000000 2800000;nand write 30008000 1000000 $filesize" ++#define CONFIG_BURN_UBIFS "tftp 30008000 rootfs-fl2440.ubi;nand erase 1000000 2800000;nand write 30008000 1000000 $filesize" ++ ++ ++#define CONFIG_BARGS_INITRAMFS "console=tty0 console=ttyS0,115200 mem=64M rw loglevel=7" ++#define CONFIG_BARGS_JFFS2 "console=tty0 console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7" ++#define CONFIG_BARGS_UBIFS "console=tty0 console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs mem=64M noinitrd rw loglevel=7" ++#define CONFIG_BOOTARGS CONFIG_BARGS_UBIFS ++#define CONFIG_BOOTCOMMAND "nand read 30008000 100000 900000; bootm 30008000" ++ ++#if defined(CONFIG_CMD_KGDB) ++#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ ++/* what's this ? it's not used anywhere */ ++#define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */ ++#endif ++ ++/* ++ * Miscellaneous configurable options ++ */ ++#define CONFIG_SYS_LONGHELP /* undef to save memory */ ++#define CONFIG_SYS_PROMPT "[fl2440@lingyun]# " /* Monitor Command Prompt */ ++#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ ++#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16) /* Print Buffer Size */ ++#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ ++#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE /* Boot Argument Buffer Size */ ++ ++#define CONFIG_SYS_MEMTEST_START 0x30000000 /* memtest works on */ ++#define CONFIG_SYS_MEMTEST_END 0x33F00000 /* 63 MB in DRAM */ ++ ++#define CONFIG_SYS_LOAD_ADDR 0x33000000 /* default load address */ ++ ++#define CONFIG_SYS_HZ 1000 ++ ++/* valid baudrates */ ++#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } ++ ++/*----------------------------------------------------------------------- ++ * Stack sizes ++ * ++ * The stack sizes are set up in start.S using the settings below ++ */ ++#define CONFIG_STACKSIZE (128*1024) /* regular stack */ ++#ifdef CONFIG_USE_IRQ ++#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */ ++#define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */ ++#endif ++ ++/*----------------------------------------------------------------------- ++ * Physical Memory Map ++ */ ++#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ ++#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */ ++#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */ ++ ++#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */ ++ ++#define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1 ++ ++#define CONFIG_SYS_NO_FLASH 1 ++#undef CONFIG_CMD_IMLS ++ ++/*----------------------------------------------------------------------- ++ * FLASH and environment organization ++ */ ++#ifndef CONFIG_SYS_NO_FLASH ++#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ ++#endif ++#if 0 ++#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ ++#endif ++ ++#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */ ++#ifdef CONFIG_AMD_LV800 ++#define PHYS_FLASH_SIZE 0x00100000 /* 1MB */ ++#define CONFIG_SYS_MAX_FLASH_SECT (19) /* max number of sectors on one chip */ ++#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x0F0000) /* addr of environment */ ++#endif ++#ifdef CONFIG_AMD_LV400 ++#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */ ++#define CONFIG_SYS_MAX_FLASH_SECT (11) /* max number of sectors on one chip */ ++#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */ ++#endif ++ ++/* timeout values are in ticks */ ++#define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */ ++#define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */ ++ ++#ifndef CONFIG_SYS_NO_FLASH ++#define CONFIG_ENV_IS_IN_FLASH 1 ++#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ ++#endif ++ ++#if defined(CONFIG_CMD_NAND) ++#define CONFIG_NAND_S3C2410 ++#define CONFIG_S3C2410_NAND_SKIP_BAD 1 ++#define CONFIG_SYS_NAND_BASE 0x4E000000 ++#define CONFIG_SYS_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ ++#define CONFIG_SYS_NAND_MAX_CHIPS 1 ++#define CONFIG_MTD_NAND_VERIFY_WRITE ++ ++#define CONFIG_ENV_IS_IN_NAND 1 ++#define CONFIG_ENV_OFFSET 0X60000 ++#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ ++#endif /* CONFIG_CMD_NAND */ ++ ++#define CONFIG_SETUP_MEMORY_TAGS ++#define CONFIG_INITRD_TAG ++#define CONFIG_CMDLINE_TAG ++ ++#define CONFIG_SYS_HUSH_PARSER ++#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " ++ ++#define CONFIG_CMDLINE_EDITING ++#ifdef CONFIG_CMDLINE_EDITING ++#undef CONFIG_AUTO_COMPLETE ++#else ++#define CONFIG_AUTO_COMPLETE ++#endif ++ ++#endif /* __CONFIG_H */ +diff -Nuar u-boot-2010.09/include/serial.h u-boot-2010.09-fl2440/include/serial.h +--- u-boot-2010.09/include/serial.h 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/include/serial.h 2020-01-09 17:22:17.709412170 +0800 +@@ -46,7 +46,7 @@ + extern struct serial_device serial6_device; + #endif + +-#if defined(CONFIG_S3C2410) ++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + extern struct serial_device s3c24xx_serial0_device; + extern struct serial_device s3c24xx_serial1_device; + extern struct serial_device s3c24xx_serial2_device; +diff -Nuar u-boot-2010.09/Makefile u-boot-2010.09-fl2440/Makefile +--- u-boot-2010.09/Makefile 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-fl2440/Makefile 2020-01-09 17:25:16.141415593 +0800 +@@ -154,6 +154,8 @@ + # load ARCH, BOARD, and CPU configuration + include $(obj)include/config.mk + export ARCH CPU BOARD VENDOR SOC ++export ARCH=arm ++export CROSS_COMPILE=/opt/xtools/arm920t/bin/arm-linux- + + # set default to nothing for native builds + ifeq ($(HOSTARCH),$(ARCH)) +@@ -317,6 +319,7 @@ + + $(obj)u-boot.bin: $(obj)u-boot + $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ ++ mv u-boot.bin u-boot-fl2440.bin + + $(obj)u-boot.ldr: $(obj)u-boot + $(CREATE_LDR_ENV) diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch new file mode 100644 index 0000000..3a31877 --- /dev/null +++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-1-basic.patch @@ -0,0 +1,1765 @@ +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/speed.c +--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/speed.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/speed.c 2015-11-16 13:12:18.660998681 +0800 +@@ -64,6 +64,11 @@ + p = ((r & 0x003F0) >> 4) + 2; + s = r & 0x3; + ++#if defined(CONFIG_S3C2440) /* Add by guowenxue*/ ++ if (pllreg == MPLL) ++ return ((CONFIG_SYS_CLK_FREQ * m * 2) /(p << s)); ++ else if (pllreg == UPLL) ++#endif /* Add end*/ + return (CONFIG_SYS_CLK_FREQ * m) / (p << s); + } + +@@ -78,7 +83,22 @@ + { + struct s3c24x0_clock_power *clk_power = s3c24x0_get_base_clock_power(); + ++#if defined(CONFIG_S3C2440) ++ if (readl(&clk_power->CLKDIVN) & 0x6) ++ { ++ if ((readl(&clk_power->CLKDIVN) & 0x6)==2) ++ return(get_FCLK()/2); ++ if ((readl(&clk_power->CLKDIVN) & 0x6)==6) ++ return((readl(&clk_power->CAMDIVN) & 0x100) ? get_FCLK()/6 : get_FCLK()/3); ++ if ((readl(&clk_power->CLKDIVN) & 0x6)==4) ++ return((readl(&clk_power->CAMDIVN) & 0x200) ? get_FCLK()/8 : get_FCLK()/4); ++ return(get_FCLK()); ++ } ++ else ++ return(get_FCLK()); ++#else + return (readl(&clk_power->CLKDIVN) & 2) ? get_FCLK() / 2 : get_FCLK(); ++#endif + } + + /* return PCLK frequency */ +@@ -95,4 +115,17 @@ + return get_PLLCLK(UPLL); + } + ++ ++#if defined(CONFIG_DISPLAY_CPUINFO) ++int print_cpuinfo(void) ++{ ++ printf("S3C2440A CPU clock : %lu MHz\n", get_FCLK()); ++ printf("S3C2440A HSB clock : %lu MHz\n", get_HCLK()); ++ printf("S3C2440A PSB clock : %lu MHz\n", get_PCLK()); ++ printf("S3C2440A USB clock : %lu MHz\n", get_FCLK()); ++ ++ return 0; ++} ++#endif ++ + #endif /* CONFIG_S3C24X0 */ +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/timer.c +--- u-boot-2010.09/arch/arm/cpu/arm920t/s3c24x0/timer.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/s3c24x0/timer.c 2015-11-16 13:12:09.988998722 +0800 +@@ -181,6 +181,7 @@ + tbclk = timer_load_val * 100; + #elif defined(CONFIG_SBC2410X) || \ + defined(CONFIG_SMDK2410) || \ ++ defined(CONFIG_FL2440) || \ + defined(CONFIG_VCMA9) + tbclk = CONFIG_SYS_HZ; + #else +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/start.S u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/start.S +--- u-boot-2010.09/arch/arm/cpu/arm920t/start.S 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/start.S 2015-11-16 13:12:09.988998722 +0800 +@@ -114,8 +114,8 @@ + orr r0, r0, #0xd3 + msr cpsr, r0 + +- bl coloured_LED_init +- bl red_LED_on ++ @bl coloured_LED_init ++ @bl red_LED_on + + #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) + /* +@@ -159,13 +159,63 @@ + ldr r1, =0x3ff + ldr r0, =INTSUBMSK + str r1, [r0] ++#elif defined CONFIG_S3C2440 ++ ldr r1, =0x7fff ++ ldr r0, =INTSUBMSK ++ str r1, [r0] + # endif + ++# if defined(CONFIG_S3C2440) ++#define GPBCON 0x56000010 ++#define GPBDAT 0x56000014 ++#define GPBUP 0x56000018 ++ /*Set GPIO5, GPIO6, GPIO8, GPIO10 as GPIO OUTPUT mode*/ ++ ldr r0, =GPBCON ++ ldr r1, [r0] ++ bic r1, r1, #0x3c00 /*Set GPBCON for GPIO5,GPIO6 as 0x00 */ ++ orr r1, r1, #0x1400 /*Set GPBCON for GPIO5,GPIO6 as GPIOOUT, 0x01*/ ++ bic r1, r1, #0x00330000 /*Set GPBCON for GPIO8,GPIO10 as 0x00*/ ++ orr r1, r1, #0x00110000 /*Set GPBCON for GPIO8,GPIO10 as GPIOOUT, 0x01*/ ++ str r1, [r0] ++ ++ /*Set internal pullup resister*/ ++ ldr r0, =GPBUP ++ ldr r1, [r0] ++ orr r1, r1, #0x0560 /*Set bit 5,6,8,10, disable pullup resister*/ ++ str r1, [r0] ++ ++ ldr r2, =GPBDAT ++ ldr r3, [r2] ++ orr r3, r3, #0x0560 /*Set bit 5,6,8,10 as high level, Turn Off LED*/ ++ str r3, [r2] ++ ++# define MPLLCON 0x4C000004 ++# define MDIV_405 0x7f << 12 ++# define PSDIV_405 0x21 ++ ++ ++ /* FCLK:HCLK:PCLK = 1:4:8 */ ++ ldr r0, =CLKDIVN ++ mov r1, #0x05 ++ str r1, [r0] ++ ++ mrc p15, 0, r1, c1, c0, 0 ++ orr r1, r1, #0xc0000000 ++ mcr p15, 0, r1, c1, c0, 0 ++ ++ Ldr r0,=MPLLCON ++ mov r1, #MDIV_405 ++ add r1, r1, #PSDIV_405 ++ str r1, [r0] ++ ++ ++#else /*S3C2410, S3C2440 */ + /* FCLK:HCLK:PCLK = 1:2:4 */ + /* default FCLK is 120 MHz ! */ + ldr r0, =CLKDIVN + mov r1, #3 + str r1, [r0] ++#endif /* end of if defined(CONFIG_S3C2440) */ + #endif /* CONFIG_S3C24X0 */ + + /* +@@ -183,6 +233,92 @@ + cmp r0, r1 /* don't reloc during debug */ + beq stack_setup + ++judgment_norflash_nandflash_boot: ++ ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) ++ mov r0, #0 ++ str r0, [r1] ++ ++ mov r1, #0x3c ++ ldr r0, [r1] ++ cmp r0, #0 ++ bne norflash_boot ++ ++ /*Nandflash boot going here, recovery address 0x0000003C date*/ ++ ldr r0, =(0xdeadbeef) ++ ldr r1, =( (4<<28)|(3<<4)|(3<<2) ) ++ str r0, [r1] ++ ++nandflash_boot: ++#define LENGTH_UBOOT 0x60000 ++#define NAND_CTL_BASE 0x4E000000 ++/* Offset */ ++#define oNFCONF 0x00 ++#define oNFCONT 0x04 ++#define oNFCMD 0x08 ++#define oNFSTAT 0x20 ++ ++ mov r1, #NAND_CTL_BASE ++ ldr r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) ++ str r2, [r1, #oNFCONF] ++ ldr r2, [r1, #oNFCONF] ++ ++ ldr r2, =( (1<<4)|(0<<1)|(1<<0) ) @ Active low CE Control ++ str r2, [r1, #oNFCONT] ++ ldr r2, [r1, #oNFCONT] ++ ++ ldr r2, =(0x6) @ RnB Clear ++ str r2, [r1, #oNFSTAT] ++ ldr r2, [r1, #oNFSTAT] ++ ++ mov r2, #0xff @ RESET command ++ strb r2, [r1, #oNFCMD] ++ ++ mov r3, #0 @ wait ++nand_delay: ++ add r3, r3, #0x1 ++ cmp r3, #0xa ++ blt nand_delay ++ ++nand_wait: ++ ldr r2, [r1, #oNFSTAT] @ wait ready ++ tst r2, #0x4 ++ beq nand_wait ++ ++ ldr r2, [r1, #oNFCONT] ++ orr r2, r2, #0x2 @ Flash Memory Chip Disable ++ str r2, [r1, #oNFCONT] ++ ++ ldr sp, DW_STACK_START @ setup stack pointer ++ mov fp, #0 @ no previous frame, so fp=0 ++ ++ ldr r0, =TEXT_BASE ++ mov r1, #0x0 ++ mov r2, #LENGTH_UBOOT ++ bl nand_read_ll ++ tst r0, #0x0 ++ bne infinite_loop /*nand_read_ll() not return 0, then goto dead loop*/ ++ ++nand_read_ok: ++ /*Then verify the read data validation*/ ++ mov r0, #0 ++ ldr r1, =TEXT_BASE ++ mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes ++ ++compare_next_byte: ++ ldr r3, [r0], #4 ++ ldr r4, [r1], #4 ++ teq r3, r4 ++ bne infinite_loop ++ ++ subs r2, r2, #4 ++ beq stack_setup ++ bne compare_next_byte ++ ++infinite_loop: ++ b infinite_loop @ infinite loop ++ ++norflash_boot: ++ + ldr r2, _armboot_start + ldr r3, _bss_start + sub r2, r3, r2 /* r2 <- size of armboot */ +@@ -216,10 +352,22 @@ + cmp r0, r1 + ble clbss_l + ++ ldr r1, =GPBDAT ++ ldr r2, [r1] ++ bic r2, r2, #(1<<5) ++ str r2, [r1] ++ + ldr pc, _start_armboot + + _start_armboot: .word start_armboot + ++#ifdef CONFIG_S3C24X0 ++#define STACK_BASE 0x33f00000 ++#define STACK_SIZE 0x10000 ++ .align 2 ++ DW_STACK_START: .word STACK_BASE+STACK_SIZE-4 ++#endif ++ + + /* + ************************************************************************* +diff -Nuar u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/u-boot.lds +--- u-boot-2010.09/arch/arm/cpu/arm920t/u-boot.lds 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/arch/arm/cpu/arm920t/u-boot.lds 2015-11-16 13:12:09.988998722 +0800 +@@ -40,6 +40,8 @@ + .text : + { + arch/arm/cpu/arm920t/start.o (.text) ++ board/lingyun/fl2440/lowlevel_init.o (.text) ++ board/lingyun/fl2440/nand_read.o (.text) + *(.text) + } + +diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h +--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0_cpu.h 2015-11-16 13:12:09.989998693 +0800 +@@ -20,7 +20,7 @@ + + #ifdef CONFIG_S3C2400 + #include <asm/arch/s3c2400.h> +-#elif defined CONFIG_S3C2410 ++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + #include <asm/arch/s3c2410.h> + #else + #error Please define the s3c24x0 cpu type +diff -Nuar u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h +--- u-boot-2010.09/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/arch/arm/include/asm/arch-s3c24x0/s3c24x0.h 2015-11-16 13:12:09.989998693 +0800 +@@ -78,7 +78,7 @@ + u32 PRIORITY; + u32 INTPND; + u32 INTOFFSET; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 SUBSRCPND; + u32 INTSUBMSK; + #endif +@@ -88,11 +88,11 @@ + /* DMAS (see manual chapter 8) */ + struct s3c24x0_dma { + u32 DISRC; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 DISRCC; + #endif + u32 DIDST; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 DIDSTC; + #endif + u32 DCON; +@@ -103,7 +103,7 @@ + #ifdef CONFIG_S3C2400 + u32 res[1]; + #endif +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 res[7]; + #endif + }; +@@ -122,6 +122,9 @@ + u32 CLKCON; + u32 CLKSLOW; + u32 CLKDIVN; ++#if defined (CONFIG_S3C2440) ++ u32 CAMDIVN; ++#endif + }; + + +@@ -141,7 +144,7 @@ + u32 res[8]; + u32 DITHMODE; + u32 TPAL; +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 LCDINTPND; + u32 LCDSRCPND; + u32 LCDINTMSK; +@@ -151,6 +154,7 @@ + + + /* NAND FLASH (see S3C2410 manual chapter 6) */ ++#if defined(CONFIG_S3C2410) + struct s3c2410_nand { + u32 NFCONF; + u32 NFCMD; +@@ -159,6 +163,26 @@ + u32 NFSTAT; + u32 NFECC; + }; ++#elif defined (CONFIG_S3C2440) ++struct s3c2410_nand { ++ u32 NFCONF; ++ u32 NFCONT; ++ u32 NFCMD; ++ u32 NFADDR; ++ u32 NFDATA; ++ u32 NFMECCD0; ++ u32 NFMECCD1; ++ u32 NFSECCD; ++ u32 NFSTAT; ++ u32 NFESTAT0; ++ u32 NFESTAT1; ++ u32 NFMECC0; ++ u32 NFMECC1; ++ u32 NFSECC; ++ u32 NFSBLK; ++ u32 NFEBLK; ++}; ++#endif + + + /* UART (see manual chapter 11) */ +@@ -397,7 +421,7 @@ + u32 MISCCR; + u32 EXTINT; + #endif +-#ifdef CONFIG_S3C2410 ++#if defined(CONFIG_S3C2410) || defined (CONFIG_S3C2440) + u32 GPACON; + u32 GPADAT; + u32 res1[2]; +@@ -446,6 +470,13 @@ + u32 GSTATUS2; + u32 GSTATUS3; + u32 GSTATUS4; ++#if defined (CONFIG_S3C2440) ++ u32 res9[3]; ++ u32 MSLCON; ++ u32 GPJCON; ++ u32 GPJDAT; ++ u32 GPJUP; ++#endif + #endif + }; + +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/config.mk u-boot-2010.09-1-basic/board/lingyun/fl2440/config.mk +--- u-boot-2010.09/board/lingyun/fl2440/config.mk 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/config.mk 2015-11-16 13:12:09.989998693 +0800 +@@ -0,0 +1,25 @@ ++# ++# (C) Copyright 2002 ++# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> ++# David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> ++# ++# SAMSUNG SMDK2410 board with S3C2410X (ARM920T) cpu ++# ++# see http://www.samsung.com/ for more information on SAMSUNG ++# ++ ++# ++# SMDK2410 has 1 bank of 64 MB DRAM ++# ++# 3000'0000 to 3400'0000 ++# ++# Linux-Kernel is expected to be at 3000'8000, entry 3000'8000 ++# optionally with a ramdisk at 3080'0000 ++# ++# we load ourself to 33F8'0000 ++# ++# download area is 3300'0000 ++# ++ ++ ++TEXT_BASE = 0x33F80000 +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-1-basic/board/lingyun/fl2440/fl2440.c +--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/fl2440.c 2015-11-16 13:15:03.314998179 +0800 +@@ -0,0 +1,171 @@ ++/* ++ * (C) Copyright 2002 ++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com> ++ * Marius Groeger <mgroeger@sysgo.de> ++ * ++ * (C) Copyright 2002 ++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 <common.h> ++#include <netdev.h> ++#include <asm/arch/s3c24x0_cpu.h> ++ ++DECLARE_GLOBAL_DATA_PTR; ++ ++#define FCLK_SPEED 1 ++ ++#if FCLK_SPEED==0 /* Fout = 203MHz, Fin = 12MHz for Audio */ ++#define M_MDIV 0xC3 ++#define M_PDIV 0x4 ++#define M_SDIV 0x1 ++#elif FCLK_SPEED==1 /* Fout = 405MHz, modify by guowenxue */ ++#define M_MDIV 0x7f ++#define M_PDIV 0x2 ++#define M_SDIV 0x1 ++#endif ++ ++#define USB_CLOCK 1 ++ ++#if USB_CLOCK==0 ++#define U_M_MDIV 0xA1 ++#define U_M_PDIV 0x3 ++#define U_M_SDIV 0x1 ++#elif USB_CLOCK==1 ++#define U_M_MDIV 0x38 /* Modify by guowenxue */ ++#define U_M_PDIV 0x3 ++#define U_M_SDIV 0x2 ++#endif ++ ++static inline void delay (unsigned long loops) ++{ ++ __asm__ volatile ("1:\n" ++ "subs %0, %1, #1\n" ++ "bne 1b":"=r" (loops):"0" (loops)); ++} ++ ++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */ ++#define BEEP 0 /* Buzzer use GPB0 */ ++#define DELAY_TIME 10000000 ++ ++void turn_beep(void) ++{ ++ int count = 2; ++ struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio(); ++ ++ gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /* Set GPB0 as GPIO output mode(0x01) */ ++ ++ while(count--) ++ { ++ gpio->GPBCON = (gpio->GPBCON|0x3)&0x1; /* Set GPB0 as GPIO output mode(0x01) */ ++ ++ gpio->GPBDAT &= ~(1<<BEEP); /* Set Beep GPIO as low level */ ++ delay(DELAY_TIME); ++ ++ gpio->GPBDAT |= 1<<BEEP; /* Set Beep GPIO as high level */ ++ delay(DELAY_TIME); ++ ++ gpio->GPBCON &= ~0x3; /* Set GPB0 as GPIO input mode(0x00) */ ++ } ++ ++ return ; ++} ++#endif ++ ++/* ++ * Miscellaneous platform dependent initialisations ++ */ ++ ++int board_init (void) ++{ ++ struct s3c24x0_clock_power * const clk_power = ++ s3c24x0_get_base_clock_power(); ++ struct s3c24x0_gpio * const gpio = s3c24x0_get_base_gpio(); ++ ++ /* to reduce PLL lock time, adjust the LOCKTIME register */ ++ clk_power->LOCKTIME = 0xFFFFFF; ++ ++ /* configure MPLL */ ++ clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV); ++ ++ /* some delay between MPLL and UPLL */ ++ delay (4000); ++ ++ /* configure UPLL */ ++ clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV); ++ ++ /* some delay between MPLL and UPLL */ ++ delay (8000); ++ ++ /* set up the I/O ports */ ++ gpio->GPACON = 0x007FFFFF; ++ gpio->GPBCON = 0x00044555; ++ gpio->GPBUP = 0x000007FF; ++ gpio->GPCCON = 0xAAAAAAAA; ++ gpio->GPCUP = 0x0000FFFF; ++ gpio->GPDCON = 0xAAAAAAAA; ++ gpio->GPDUP = 0x0000FFFF; ++ gpio->GPECON = 0xAAAAAAAA; ++ gpio->GPEUP = 0x0000FFFF; ++ gpio->GPFCON = 0x000055AA; ++ gpio->GPFUP = 0x000000FF; ++ gpio->GPGCON = 0xFF95FFBA; ++ gpio->GPGUP = 0x0000FFFF; ++ gpio->GPHCON = 0x002AFAAA; ++ gpio->GPHUP = 0x000007FF; ++ ++ /* arch number of SMDK2410-Board */ ++ gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; ++ ++ /* adress of boot parameters */ ++ gd->bd->bi_boot_params = 0x30000100; ++ ++ icache_enable(); ++ dcache_enable(); ++ ++#if defined(CONFIG_FL2440_LED) /* Add by guowenxue, 2012.10.04 */ ++ gpio->GPBDAT = 0x00000181; ++#endif ++#ifdef CONFIG_FL2440_BEEP /* Add by guowenxue, 2012.10.04 */ ++ turn_beep(); ++#endif ++ ++ return 0; ++} ++ ++int dram_init (void) ++{ ++ gd->bd->bi_dram[0].start = PHYS_SDRAM_1; ++ gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE; ++ ++ return 0; ++} ++ ++#ifdef CONFIG_CMD_NET ++int board_eth_init(bd_t *bis) ++{ ++ int rc = 0; ++#ifdef CONFIG_CS8900 ++ rc = cs8900_initialize(0, CONFIG_CS8900_BASE); ++#endif ++ return rc; ++} ++#endif +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/flash.c u-boot-2010.09-1-basic/board/lingyun/fl2440/flash.c +--- u-boot-2010.09/board/lingyun/fl2440/flash.c 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/flash.c 2015-11-16 13:12:09.991998636 +0800 +@@ -0,0 +1,433 @@ ++/* ++ * (C) Copyright 2002 ++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com> ++ * Alex Zuepke <azu@sysgo.de> ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 <common.h> ++ ++ulong myflush (void); ++ ++ ++#define FLASH_BANK_SIZE PHYS_FLASH_SIZE ++#define MAIN_SECT_SIZE 0x10000 /* 64 KB */ ++ ++flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; ++ ++ ++#define CMD_READ_ARRAY 0x000000F0 ++#define CMD_UNLOCK1 0x000000AA ++#define CMD_UNLOCK2 0x00000055 ++#define CMD_ERASE_SETUP 0x00000080 ++#define CMD_ERASE_CONFIRM 0x00000030 ++#define CMD_PROGRAM 0x000000A0 ++#define CMD_UNLOCK_BYPASS 0x00000020 ++ ++#define MEM_FLASH_ADDR1 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x00000555 << 1))) ++#define MEM_FLASH_ADDR2 (*(volatile u16 *)(CONFIG_SYS_FLASH_BASE + (0x000002AA << 1))) ++ ++#define BIT_ERASE_DONE 0x00000080 ++#define BIT_RDY_MASK 0x00000080 ++#define BIT_PROGRAM_ERROR 0x00000020 ++#define BIT_TIMEOUT 0x80000000 /* our flag */ ++ ++#define READY 1 ++#define ERR 2 ++#define TMO 4 ++ ++/*----------------------------------------------------------------------- ++ */ ++ ++ulong flash_init (void) ++{ ++ int i, j; ++ ulong size = 0; ++ ++ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) { ++ ulong flashbase = 0; ++ ++ flash_info[i].flash_id = ++#if defined(CONFIG_AMD_LV400) ++ (AMD_MANUFACT & FLASH_VENDMASK) | ++ (AMD_ID_LV400B & FLASH_TYPEMASK); ++#elif defined(CONFIG_AMD_LV800) ++ (AMD_MANUFACT & FLASH_VENDMASK) | ++ (AMD_ID_LV800B & FLASH_TYPEMASK); ++#else ++#error "Unknown flash configured" ++#endif ++ flash_info[i].size = FLASH_BANK_SIZE; ++ flash_info[i].sector_count = CONFIG_SYS_MAX_FLASH_SECT; ++ memset (flash_info[i].protect, 0, CONFIG_SYS_MAX_FLASH_SECT); ++ if (i == 0) ++ flashbase = PHYS_FLASH_1; ++ else ++ panic ("configured too many flash banks!\n"); ++ for (j = 0; j < flash_info[i].sector_count; j++) { ++ if (j <= 3) { ++ /* 1st one is 16 KB */ ++ if (j == 0) { ++ flash_info[i].start[j] = ++ flashbase + 0; ++ } ++ ++ /* 2nd and 3rd are both 8 KB */ ++ if ((j == 1) || (j == 2)) { ++ flash_info[i].start[j] = ++ flashbase + 0x4000 + (j - ++ 1) * ++ 0x2000; ++ } ++ ++ /* 4th 32 KB */ ++ if (j == 3) { ++ flash_info[i].start[j] = ++ flashbase + 0x8000; ++ } ++ } else { ++ flash_info[i].start[j] = ++ flashbase + (j - 3) * MAIN_SECT_SIZE; ++ } ++ } ++ size += flash_info[i].size; ++ } ++ ++ flash_protect (FLAG_PROTECT_SET, ++ CONFIG_SYS_FLASH_BASE, ++ CONFIG_SYS_FLASH_BASE + monitor_flash_len - 1, ++ &flash_info[0]); ++ ++ flash_protect (FLAG_PROTECT_SET, ++ CONFIG_ENV_ADDR, ++ CONFIG_ENV_ADDR + CONFIG_ENV_SIZE - 1, &flash_info[0]); ++ ++ return size; ++} ++ ++/*----------------------------------------------------------------------- ++ */ ++void flash_print_info (flash_info_t * info) ++{ ++ int i; ++ ++ switch (info->flash_id & FLASH_VENDMASK) { ++ case (AMD_MANUFACT & FLASH_VENDMASK): ++ printf ("AMD: "); ++ break; ++ default: ++ printf ("Unknown Vendor "); ++ break; ++ } ++ ++ switch (info->flash_id & FLASH_TYPEMASK) { ++ case (AMD_ID_LV400B & FLASH_TYPEMASK): ++ printf ("1x Amd29LV400BB (4Mbit)\n"); ++ break; ++ case (AMD_ID_LV800B & FLASH_TYPEMASK): ++ printf ("1x Amd29LV800BB (8Mbit)\n"); ++ break; ++ default: ++ printf ("Unknown Chip Type\n"); ++ goto Done; ++ break; ++ } ++ ++ printf (" Size: %ld MB in %d Sectors\n", ++ info->size >> 20, info->sector_count); ++ ++ printf (" Sector Start Addresses:"); ++ for (i = 0; i < info->sector_count; i++) { ++ if ((i % 5) == 0) { ++ printf ("\n "); ++ } ++ printf (" %08lX%s", info->start[i], ++ info->protect[i] ? " (RO)" : " "); ++ } ++ printf ("\n"); ++ ++ Done:; ++} ++ ++/*----------------------------------------------------------------------- ++ */ ++ ++int flash_erase (flash_info_t * info, int s_first, int s_last) ++{ ++ ushort result; ++ int iflag, cflag, prot, sect; ++ int rc = ERR_OK; ++ int chip; ++ ++ /* first look for protection bits */ ++ ++ if (info->flash_id == FLASH_UNKNOWN) ++ return ERR_UNKNOWN_FLASH_TYPE; ++ ++ if ((s_first < 0) || (s_first > s_last)) { ++ return ERR_INVAL; ++ } ++ ++ if ((info->flash_id & FLASH_VENDMASK) != ++ (AMD_MANUFACT & FLASH_VENDMASK)) { ++ return ERR_UNKNOWN_FLASH_VENDOR; ++ } ++ ++ prot = 0; ++ for (sect = s_first; sect <= s_last; ++sect) { ++ if (info->protect[sect]) { ++ prot++; ++ } ++ } ++ if (prot) ++ return ERR_PROTECTED; ++ ++ /* ++ * Disable interrupts which might cause a timeout ++ * here. Remember that our exception vectors are ++ * at address 0 in the flash, and we don't want a ++ * (ticker) exception to happen while the flash ++ * chip is in programming mode. ++ */ ++ cflag = icache_status (); ++ icache_disable (); ++ iflag = disable_interrupts (); ++ ++ /* Start erase on unprotected sectors */ ++ for (sect = s_first; sect <= s_last && !ctrlc (); sect++) { ++ printf ("Erasing sector %2d ... ", sect); ++ ++ /* arm simple, non interrupt dependent timer */ ++ reset_timer_masked (); ++ ++ if (info->protect[sect] == 0) { /* not protected */ ++ vu_short *addr = (vu_short *) (info->start[sect]); ++ ++ MEM_FLASH_ADDR1 = CMD_UNLOCK1; ++ MEM_FLASH_ADDR2 = CMD_UNLOCK2; ++ MEM_FLASH_ADDR1 = CMD_ERASE_SETUP; ++ ++ MEM_FLASH_ADDR1 = CMD_UNLOCK1; ++ MEM_FLASH_ADDR2 = CMD_UNLOCK2; ++ *addr = CMD_ERASE_CONFIRM; ++ ++ /* wait until flash is ready */ ++ chip = 0; ++ ++ do { ++ result = *addr; ++ ++ /* check timeout */ ++ if (get_timer_masked () > ++ CONFIG_SYS_FLASH_ERASE_TOUT) { ++ MEM_FLASH_ADDR1 = CMD_READ_ARRAY; ++ chip = TMO; ++ break; ++ } ++ ++ if (!chip ++ && (result & 0xFFFF) & BIT_ERASE_DONE) ++ chip = READY; ++ ++ if (!chip ++ && (result & 0xFFFF) & BIT_PROGRAM_ERROR) ++ chip = ERR; ++ ++ } while (!chip); ++ ++ MEM_FLASH_ADDR1 = CMD_READ_ARRAY; ++ ++ if (chip == ERR) { ++ rc = ERR_PROG_ERROR; ++ goto outahere; ++ } ++ if (chip == TMO) { ++ rc = ERR_TIMOUT; ++ goto outahere; ++ } ++ ++ printf ("ok.\n"); ++ } else { /* it was protected */ ++ ++ printf ("protected!\n"); ++ } ++ } ++ ++ if (ctrlc ()) ++ printf ("User Interrupt!\n"); ++ ++ outahere: ++ /* allow flash to settle - wait 10 ms */ ++ udelay_masked (10000); ++ ++ if (iflag) ++ enable_interrupts (); ++ ++ if (cflag) ++ icache_enable (); ++ ++ return rc; ++} ++ ++/*----------------------------------------------------------------------- ++ * Copy memory to flash ++ */ ++ ++static int write_hword (flash_info_t * info, ulong dest, ushort data) ++{ ++ vu_short *addr = (vu_short *) dest; ++ ushort result; ++ int rc = ERR_OK; ++ int cflag, iflag; ++ int chip; ++ ++ /* ++ * Check if Flash is (sufficiently) erased ++ */ ++ result = *addr; ++ if ((result & data) != data) ++ return ERR_NOT_ERASED; ++ ++ ++ /* ++ * Disable interrupts which might cause a timeout ++ * here. Remember that our exception vectors are ++ * at address 0 in the flash, and we don't want a ++ * (ticker) exception to happen while the flash ++ * chip is in programming mode. ++ */ ++ cflag = icache_status (); ++ icache_disable (); ++ iflag = disable_interrupts (); ++ ++ MEM_FLASH_ADDR1 = CMD_UNLOCK1; ++ MEM_FLASH_ADDR2 = CMD_UNLOCK2; ++ MEM_FLASH_ADDR1 = CMD_UNLOCK_BYPASS; ++ *addr = CMD_PROGRAM; ++ *addr = data; ++ ++ /* arm simple, non interrupt dependent timer */ ++ reset_timer_masked (); ++ ++ /* wait until flash is ready */ ++ chip = 0; ++ do { ++ result = *addr; ++ ++ /* check timeout */ ++ if (get_timer_masked () > CONFIG_SYS_FLASH_ERASE_TOUT) { ++ chip = ERR | TMO; ++ break; ++ } ++ if (!chip && ((result & 0x80) == (data & 0x80))) ++ chip = READY; ++ ++ if (!chip && ((result & 0xFFFF) & BIT_PROGRAM_ERROR)) { ++ result = *addr; ++ ++ if ((result & 0x80) == (data & 0x80)) ++ chip = READY; ++ else ++ chip = ERR; ++ } ++ ++ } while (!chip); ++ ++ *addr = CMD_READ_ARRAY; ++ ++ if (chip == ERR || *addr != data) ++ rc = ERR_PROG_ERROR; ++ ++ if (iflag) ++ enable_interrupts (); ++ ++ if (cflag) ++ icache_enable (); ++ ++ return rc; ++} ++ ++/*----------------------------------------------------------------------- ++ * Copy memory to flash. ++ */ ++ ++int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) ++{ ++ ulong cp, wp; ++ int l; ++ int i, rc; ++ ushort data; ++ ++ wp = (addr & ~1); /* get lower word aligned address */ ++ ++ /* ++ * handle unaligned start bytes ++ */ ++ if ((l = addr - wp) != 0) { ++ data = 0; ++ for (i = 0, cp = wp; i < l; ++i, ++cp) { ++ data = (data >> 8) | (*(uchar *) cp << 8); ++ } ++ for (; i < 2 && cnt > 0; ++i) { ++ data = (data >> 8) | (*src++ << 8); ++ --cnt; ++ ++cp; ++ } ++ for (; cnt == 0 && i < 2; ++i, ++cp) { ++ data = (data >> 8) | (*(uchar *) cp << 8); ++ } ++ ++ if ((rc = write_hword (info, wp, data)) != 0) { ++ return (rc); ++ } ++ wp += 2; ++ } ++ ++ /* ++ * handle word aligned part ++ */ ++ while (cnt >= 2) { ++ data = *((vu_short *) src); ++ if ((rc = write_hword (info, wp, data)) != 0) { ++ return (rc); ++ } ++ src += 2; ++ wp += 2; ++ cnt -= 2; ++ } ++ ++ if (cnt == 0) { ++ return ERR_OK; ++ } ++ ++ /* ++ * handle unaligned tail bytes ++ */ ++ data = 0; ++ for (i = 0, cp = wp; i < 2 && cnt > 0; ++i, ++cp) { ++ data = (data >> 8) | (*src++ << 8); ++ --cnt; ++ } ++ for (; i < 2; ++i, ++cp) { ++ data = (data >> 8) | (*(uchar *) cp << 8); ++ } ++ ++ return write_hword (info, wp, data); ++} +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S u-boot-2010.09-1-basic/board/lingyun/fl2440/lowlevel_init.S +--- u-boot-2010.09/board/lingyun/fl2440/lowlevel_init.S 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/lowlevel_init.S 2015-11-16 13:12:09.991998636 +0800 +@@ -0,0 +1,198 @@ ++/* ++ * Memory Setup stuff - taken from blob memsetup.S ++ * ++ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and ++ * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) ++ * ++ * Modified for the Samsung SMDK2410 by ++ * (C) Copyright 2002 ++ * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch> ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 <config.h> ++#include <version.h> ++ ++ ++/* some parameters for the board */ ++ ++/* ++ * ++ * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S ++ * ++ * Copyright (C) 2002 Samsung Electronics SW.LEE <hitchcar@sec.samsung.com> ++ * ++ */ ++ ++#define BWSCON 0x48000000 ++#define GPBCON 0x56000010 ++#define GPBDAT 0x56000014 ++#define GPBUP 0x56000018 ++ ++/* BWSCON */ ++#define DW8 (0x0) ++#define DW16 (0x1) ++#define DW32 (0x2) ++#define WAIT (0x1<<2) ++#define UBLB (0x1<<3) ++ ++#define B1_BWSCON (DW32) ++#define B2_BWSCON (DW16) ++#define B3_BWSCON (DW16 + WAIT + UBLB) ++#define B4_BWSCON (DW16) ++#define B5_BWSCON (DW16) ++#define B6_BWSCON (DW32) ++#define B7_BWSCON (DW32) ++ ++/* BANK0CON */ ++#define B0_Tacs 0x0 /* 0clk */ ++#define B0_Tcos 0x0 /* 0clk */ ++#define B0_Tacc 0x7 /* 14clk */ ++#define B0_Tcoh 0x0 /* 0clk */ ++#define B0_Tah 0x0 /* 0clk */ ++#define B0_Tacp 0x0 ++#define B0_PMC 0x0 /* normal */ ++ ++/* BANK1CON */ ++#define B1_Tacs 0x0 /* 0clk */ ++#define B1_Tcos 0x0 /* 0clk */ ++#define B1_Tacc 0x7 /* 14clk */ ++#define B1_Tcoh 0x0 /* 0clk */ ++#define B1_Tah 0x0 /* 0clk */ ++#define B1_Tacp 0x0 ++#define B1_PMC 0x0 ++ ++#define B2_Tacs 0x0 ++#define B2_Tcos 0x0 ++#define B2_Tacc 0x7 ++#define B2_Tcoh 0x0 ++#define B2_Tah 0x0 ++#define B2_Tacp 0x0 ++#define B2_PMC 0x0 ++ ++#define B3_Tacs 0x0 /* 0clk */ ++#define B3_Tcos 0x3 /* 4clk */ ++#define B3_Tacc 0x7 /* 14clk */ ++#define B3_Tcoh 0x1 /* 1clk */ ++#define B3_Tah 0x0 /* 0clk */ ++#define B3_Tacp 0x3 /* 6clk */ ++#define B3_PMC 0x0 /* normal */ ++ ++#define B4_Tacs 0x0 /* 0clk */ ++#define B4_Tcos 0x0 /* 0clk */ ++#define B4_Tacc 0x7 /* 14clk */ ++#define B4_Tcoh 0x0 /* 0clk */ ++#define B4_Tah 0x0 /* 0clk */ ++#define B4_Tacp 0x0 ++#define B4_PMC 0x0 /* normal */ ++ ++#define B5_Tacs 0x0 /* 0clk */ ++#define B5_Tcos 0x0 /* 0clk */ ++#define B5_Tacc 0x7 /* 14clk */ ++#define B5_Tcoh 0x0 /* 0clk */ ++#define B5_Tah 0x0 /* 0clk */ ++#define B5_Tacp 0x0 ++#define B5_PMC 0x0 /* normal */ ++ ++/* SDRAM is on HSB bus, so its clock is from HCLK, FCLK=400, HCLK=100; so SDRAM 1clk=10ns */ ++ ++#define B6_MT 0x3 /* SDRAM */ ++// K4S561632 datasheet: RAS to CAS delay(Trcd) Min value should be 18/20ns, HCLK is 100MHz, so 1clk=10ns ++// EM63A165 datasheet: RAS# to CAS# delay(Trcd) Min value should be 15/20ns, HCLK is 100MHz, so 1clk=10ns ++#define B6_Trcd 0x2 /* 4clk */ ++#define B6_SCAN 0x1 /* 9bit */ ++ ++#define B7_MT 0x3 /* SDRAM */ ++#define B7_Trcd 0x1 /* 3clk */ ++#define B7_SCAN 0x1 /* 9bit */ ++ ++/* REFRESH register<0x48000024> parameter */ ++#define REFEN 0x1 /* Refresh enable */ ++#define TREFMD 0x0 /* CBR(CAS before RAS)/Auto refresh */ ++ ++// Trp: Row precharge time ++// K4S561632 datasheet: Min(Trp) value should be 18/20ns; ++// EM63A165 datasheet: Min value should be 15/20ns; ++#define Trp 0x2 /* 4clk */ ++ ++// Trc: Row cycle time ++// K4S561632 datasheet: Min value should be 60/65ns; ++// EM63A165 datasheet: Min value should be 60/63ns; ++// S3C2440 datasheet: REFRESH register describe: SDRAM Row cycle time: Trc=Tsrc+Trp ++#define Tsrc 0x2 /* 6clk, so Trc=Tsrc+Trp=6+3=9clk */ ++ ++// K4S561632 datasheet: 64ms refresh period (8K Cycle): 64000/8192=7.81us ++// EM63A165 datasheet: 8192 refresh cycles/64ms: 64000/8192=7.81us ++// S3C2440 datasheet: REFRESH Register Refresh period = (2^11-refresh_count+1)/HCLK ++// So Refresh count = 2^11 + 1 - 100x7.81 = 1268 ++#define REFCNT 1268 ++//#define REFCNT 489 /* HCLK=100Mhz, (2048+1-15.6*100) */ ++ ++ ++/**************************************/ ++ ++_TEXT_BASE: ++ .word TEXT_BASE ++ ++.globl lowlevel_init ++lowlevel_init: ++ ldr r5, =GPBDAT ++ ldr r6, [r5] ++ bic r6, r6, #(1<<8) ++ str r6, [r5] ++ ++ /* memory control configuration */ ++ /* make r0 relative the current location so that it */ ++ /* reads SMRDATA out of FLASH rather than memory ! */ ++ ldr r0, =SMRDATA ++ ldr r1, =lowlevel_init ++ sub r0, r0, r1 ++ adr r3, lowlevel_init /* r3 <- current position of code */ ++ add r0, r0, r3 ++ ldr r1, =BWSCON /* Bus Width Status Controller */ ++ add r2, r0, #13*4 ++ ++0: ++ ldr r3, [r0], #4 ++ str r3, [r1], #4 ++ cmp r2, r0 ++ bne 0b ++ ++ /* everything is fine now */ ++ mov pc, lr ++ ++ .ltorg ++/* the literal pools origin */ ++ ++SMRDATA: ++ .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28)) ++ .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) ++ .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) ++ .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) ++ .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) ++ .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) ++ .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) ++ .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN)) ++ .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN)) ++ .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Tsrc<<18)+REFCNT) ++ .word 0xb2 ++ .word 0x30 ++ .word 0x30 +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/Makefile u-boot-2010.09-1-basic/board/lingyun/fl2440/Makefile +--- u-boot-2010.09/board/lingyun/fl2440/Makefile 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/Makefile 2015-11-16 13:12:09.991998636 +0800 +@@ -0,0 +1,51 @@ ++# ++# (C) Copyright 2000-2006 ++# Wolfgang Denk, DENX Software Engineering, wd@denx.de. ++# ++# See file CREDITS for list of people who contributed to this ++# project. ++# ++# 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 $(TOPDIR)/config.mk ++ ++LIB = $(obj)lib$(BOARD).a ++ ++COBJS := fl2440.o nand_read.o flash.o ++SOBJS := lowlevel_init.o ++ ++SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) ++OBJS := $(addprefix $(obj),$(COBJS)) ++SOBJS := $(addprefix $(obj),$(SOBJS)) ++ ++$(LIB): $(obj).depend $(OBJS) $(SOBJS) ++ $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) ++ ++clean: ++ rm -f $(SOBJS) $(OBJS) ++ ++distclean: clean ++ rm -f $(LIB) core *.bak $(obj).depend ++ ++######################################################################### ++ ++# defines $(obj).depend target ++include $(SRCTREE)/rules.mk ++ ++sinclude $(obj).depend ++ ++######################################################################### +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/nand_read.c u-boot-2010.09-1-basic/board/lingyun/fl2440/nand_read.c +--- u-boot-2010.09/board/lingyun/fl2440/nand_read.c 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-1-basic/board/lingyun/fl2440/nand_read.c 2015-11-16 13:12:09.991998636 +0800 +@@ -0,0 +1,212 @@ ++/* ++ * nand_read.c: Simple NAND read functions for booting from NAND ++ * ++ * This is used by cpu/arm920/start.S assembler code, ++ * and the board-specific linker script must make sure this ++ * file is linked within the first 4kB of NAND flash. ++ * ++ * Taken from GPLv2 licensed vivi bootloader, ++ * Copyright (C) 2002 MIZI Research, Inc. ++ * ++ * Author: Hwang, Chideok <hwang@mizi.com> ++ * Date : $Date: 2004/02/04 10:37:37 $ ++ * ++ * u-boot integration and bad-block skipping (C) 2006 by OpenMoko, Inc. ++ * Author: Harald Welte <laforge@openmoko.org> ++ */ ++ ++#include <common.h> ++#include <linux/mtd/nand.h> ++ ++ ++#define __REGb(x) (*(volatile unsigned char *)(x)) ++#define __REGw(x) (*(volatile unsigned short *)(x)) ++#define __REGi(x) (*(volatile unsigned int *)(x)) ++#define NF_BASE 0x4e000000 ++#if defined(CONFIG_S3C2410) ++#define NFCONF __REGi(NF_BASE + 0x0) ++#define NFCMD __REGb(NF_BASE + 0x4) ++#define NFADDR __REGb(NF_BASE + 0x8) ++#define NFDATA __REGb(NF_BASE + 0xc) ++#define NFSTAT __REGb(NF_BASE + 0x10) ++#define NFSTAT_BUSY 1 ++#define nand_select() (NFCONF &= ~0x800) ++#define nand_deselect() (NFCONF |= 0x800) ++#define nand_clear_RnB() do {} while (0) ++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) ++#define NFCONF __REGi(NF_BASE + 0x0) ++#define NFCONT __REGi(NF_BASE + 0x4) ++#define NFCMD __REGb(NF_BASE + 0x8) ++#define NFADDR __REGb(NF_BASE + 0xc) ++#define NFDATA __REGb(NF_BASE + 0x10) ++#define NFDATA16 __REGw(NF_BASE + 0x10) ++#define NFSTAT __REGb(NF_BASE + 0x20) ++#define NFSTAT_BUSY 1 ++#define nand_select() (NFCONT &= ~(1 << 1)) ++#define nand_deselect() (NFCONT |= (1 << 1)) ++#define nand_clear_RnB() (NFSTAT |= (1 << 2)) ++#endif ++ ++static inline void nand_wait(void) ++{ ++ int i; ++ ++ while (!(NFSTAT & NFSTAT_BUSY)) ++ for (i=0; i<10; i++); ++} ++ ++struct boot_nand_t { ++ int page_size; ++ int block_size; ++ int bad_block_offset; ++}; ++ ++static int is_bad_block(struct boot_nand_t * nand, unsigned long i) ++{ ++ unsigned char data; ++ unsigned long page_num; ++ ++ nand_clear_RnB(); ++ if (nand->page_size == 512) { ++ NFCMD = NAND_CMD_READOOB; /* 0x50 */ ++ NFADDR = nand->bad_block_offset & 0xf; ++ NFADDR = (i >> 9) & 0xff; ++ NFADDR = (i >> 17) & 0xff; ++ NFADDR = (i >> 25) & 0xff; ++ } else if (nand->page_size == 2048) { ++ page_num = i >> 11; /* addr / 2048 */ ++ NFCMD = NAND_CMD_READ0; ++ NFADDR = nand->bad_block_offset & 0xff; ++ NFADDR = (nand->bad_block_offset >> 8) & 0xff; ++ NFADDR = page_num & 0xff; ++ NFADDR = (page_num >> 8) & 0xff; ++ NFADDR = (page_num >> 16) & 0xff; ++ NFCMD = NAND_CMD_READSTART; ++ } else { ++ return -1; ++ } ++ nand_wait(); ++ data = (NFDATA & 0xff); ++ if (data != 0xff) ++ return 1; ++ ++ return 0; ++} ++ ++static int nand_read_page_ll(struct boot_nand_t * nand, unsigned char *buf, unsigned long addr) ++{ ++ unsigned short *ptr16 = (unsigned short *)buf; ++ unsigned int i, page_num; ++ ++ nand_clear_RnB(); ++ ++ NFCMD = NAND_CMD_READ0; ++ ++ if (nand->page_size == 512) { ++ /* Write Address */ ++ NFADDR = addr & 0xff; ++ NFADDR = (addr >> 9) & 0xff; ++ NFADDR = (addr >> 17) & 0xff; ++ NFADDR = (addr >> 25) & 0xff; ++ } else if (nand->page_size == 2048) { ++ page_num = addr >> 11; /* addr / 2048 */ ++ /* Write Address */ ++ NFADDR = 0; ++ NFADDR = 0; ++ NFADDR = page_num & 0xff; ++ NFADDR = (page_num >> 8) & 0xff; ++ NFADDR = (page_num >> 16) & 0xff; ++ NFCMD = NAND_CMD_READSTART; ++ } else { ++ return -1; ++ } ++ nand_wait(); ++ ++#if defined(CONFIG_S3C2410) ++ for (i = 0; i < nand->page_size; i++) { ++ *buf = (NFDATA & 0xff); ++ buf++; ++ } ++#elif defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) ++ for (i = 0; i < (nand->page_size>>1); i++) { ++ *ptr16 = NFDATA16; ++ ptr16++; ++ } ++#endif ++ ++ return nand->page_size; ++} ++ ++static unsigned short nand_read_id() ++{ ++ unsigned short res = 0; ++ NFCMD = NAND_CMD_READID; ++ NFADDR = 0; ++ res = NFDATA; ++ res = (res << 8) | NFDATA; ++ return res; ++} ++ ++extern unsigned int dynpart_size[]; ++ ++/* low level nand read function */ ++int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) ++{ ++ int i, j; ++ unsigned short nand_id; ++ struct boot_nand_t nand; ++ ++ /* chip Enable */ ++ nand_select(); ++ nand_clear_RnB(); ++ ++ for (i = 0; i < 10; i++) ++ ; ++ nand_id = nand_read_id(); ++ if (0) { /* dirty little hack to detect if nand id is misread */ ++ unsigned short * nid = (unsigned short *)0x31fffff0; ++ *nid = nand_id; ++ } ++ ++ if (nand_id == 0xec76 || /* Samsung K91208 on SD2410 board */ ++ nand_id == 0xad76 ) { /*Hynix HY27US08121A*/ ++ nand.page_size = 512; ++ nand.block_size = 16 * 1024; ++ nand.bad_block_offset = 5; ++ // nand.size = 0x4000000; ++ } else if (nand_id == 0xecf1 || /* Samsung K9F1G08U0B */ ++ nand_id == 0xadda || /* Hynix HY27UF082G2B on FL2440 board */ ++ nand_id == 0xecda || /* Samsung K9F2G08U0B on FL2440 board */ ++ nand_id == 0xecd3 ) { /* Samsung K9K8G08 */ ++ nand.page_size = 2048; ++ nand.block_size = 128 * 1024; ++ nand.bad_block_offset = nand.page_size; ++ // nand.size = 0x8000000; ++ } else { ++ return -1; // hang ++ } ++ if ((start_addr & (nand.block_size-1)) || (size & ((nand.block_size-1)))) ++ return -1; /* invalid alignment */ ++ ++ for (i=start_addr; i < (start_addr + size);) { ++#ifdef CONFIG_S3C2410_NAND_SKIP_BAD ++ if (i & (nand.block_size-1)== 0) { ++ if (is_bad_block(&nand, i) || ++ is_bad_block(&nand, i + nand.page_size)) { ++ /* Bad block */ ++ i += nand.block_size; ++ size += nand.block_size; ++ continue; ++ } ++ } ++#endif ++ j = nand_read_page_ll(&nand, buf, i); ++ i += j; ++ buf += j; ++ } ++ ++ /* chip Disable */ ++ nand_deselect(); ++ ++ return 0; ++} +diff -Nuar u-boot-2010.09/boards.cfg u-boot-2010.09-1-basic/boards.cfg +--- u-boot-2010.09/boards.cfg 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/boards.cfg 2015-11-16 13:12:09.991998636 +0800 +@@ -238,6 +238,7 @@ + sbc2410x arm arm920t - - s3c24x0 + smdk2400 arm arm920t - samsung s3c24x0 + smdk2410 arm arm920t - samsung s3c24x0 ++fl2440 arm arm920t fl2440 lingyun s3c24x0 + voiceblue arm arm925t + omap1510inn arm arm925t - ti + afeb9260 arm arm926ejs - - at91 +diff -Nuar u-boot-2010.09/common/serial.c u-boot-2010.09-1-basic/common/serial.c +--- u-boot-2010.09/common/serial.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/common/serial.c 2015-11-16 13:12:09.991998636 +0800 +@@ -68,7 +68,7 @@ + #else + #error "Bad CONFIG_PSC_CONSOLE." + #endif +-#elif defined(CONFIG_S3C2410) ++#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + #if defined(CONFIG_SERIAL1) + return &s3c24xx_serial0_device; + #elif defined(CONFIG_SERIAL2) +@@ -157,7 +157,7 @@ + #if defined (CONFIG_STUART) + serial_register(&serial_stuart_device); + #endif +-#if defined(CONFIG_S3C2410) ++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + serial_register(&s3c24xx_serial0_device); + serial_register(&s3c24xx_serial1_device); + serial_register(&s3c24xx_serial2_device); +diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-1-basic/include/configs/fl2440.h +--- u-boot-2010.09/include/configs/fl2440.h 1970-01-01 08:00:00.000000000 +0800 ++++ u-boot-2010.09-1-basic/include/configs/fl2440.h 2015-11-16 13:15:25.644998137 +0800 +@@ -0,0 +1,187 @@ ++/* ++ * (C) Copyright 2002 ++ * Sysgo Real-Time Solutions, GmbH <www.elinos.com> ++ * Marius Groeger <mgroeger@sysgo.de> ++ * Gary Jennejohn <garyj@denx.de> ++ * David Mueller <d.mueller@elsoft.ch> ++ * ++ * Configuation settings for the SAMSUNG SMDK2410 board. ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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 ++ */ ++ ++#ifndef __CONFIG_H ++#define __CONFIG_H ++ ++/* ++ * High Level Configuration Options ++ * (easy to change) ++ */ ++#define CONFIG_ARM920T 1 /* This is an ARM920T Core */ ++#define CONFIG_S3C24X0 1 /* in a SAMSUNG S3C24x0-type SoC */ ++#define CONFIG_S3C2440 1 /* specifically a SAMSUNG S3C2440 SoC */ ++#define CONFIG_FL2440 1 /* FL2440 board */ ++ ++#define CONFIG_FL2440_LED 1 ++#define CONFIG_FL2440_BEEP 1 ++#define CONFIG_S3C2410_NAND_SKIP_BAD 1 ++ ++/* input clock of PLL */ ++#define CONFIG_SYS_CLK_FREQ 12000000/* the SMDK2410 has 12MHz input clock */ ++ ++ ++#define USE_920T_MMU 1 ++#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */ ++ ++/* ++ * Size of malloc() pool ++ */ ++#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + 128*1024) ++#define CONFIG_SYS_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */ ++ ++/* ++ * Hardware drivers ++ */ ++#define CONFIG_NET_MULTI ++#define CONFIG_CS8900 /* we have a CS8900 on-board */ ++#define CONFIG_CS8900_BASE 0x19000300 ++#define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */ ++ ++/* ++ * select serial console configuration ++ */ ++#define CONFIG_S3C24X0_SERIAL ++#define CONFIG_SERIAL1 1 /* we use SERIAL 1 on SMDK2410 */ ++ ++/************************************************************ ++ * RTC ++ ************************************************************/ ++#define CONFIG_RTC_S3C24X0 1 ++ ++/* allow to overwrite serial and ethaddr */ ++#define CONFIG_ENV_OVERWRITE ++ ++#define CONFIG_BAUDRATE 115200 ++ ++ ++/* ++ * BOOTP options ++ */ ++#define CONFIG_BOOTP_BOOTFILESIZE ++#define CONFIG_BOOTP_BOOTPATH ++#define CONFIG_BOOTP_GATEWAY ++#define CONFIG_BOOTP_HOSTNAME ++ ++ ++/* ++ * Command line configuration. ++ */ ++#include <config_cmd_default.h> ++ ++#define CONFIG_CMD_CACHE ++#define CONFIG_CMD_DATE ++#define CONFIG_CMD_ELF ++ ++ ++#define CONFIG_BOOTDELAY 2 ++/*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" */ ++/*#define CONFIG_ETHADDR 08:00:3e:26:0a:5b */ ++#define CONFIG_NETMASK 255.255.255.0 ++#define CONFIG_IPADDR 10.0.0.110 ++#define CONFIG_SERVERIP 10.0.0.1 ++/*#define CONFIG_BOOTFILE "elinos-lart" */ ++/*#define CONFIG_BOOTCOMMAND "tftp; bootm" */ ++ ++#if defined(CONFIG_CMD_KGDB) ++#define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ ++/* what's this ? it's not used anywhere */ ++#define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */ ++#endif ++ ++/* ++ * Miscellaneous configurable options ++ */ ++#define CONFIG_SYS_LONGHELP /* undef to save memory */ ++#define CONFIG_SYS_PROMPT "[fl2440@lingyun]# " /* Monitor Command Prompt */ ++#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ ++#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16) /* Print Buffer Size */ ++#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ ++#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE /* Boot Argument Buffer Size */ ++ ++#define CONFIG_SYS_MEMTEST_START 0x30000000 /* memtest works on */ ++#define CONFIG_SYS_MEMTEST_END 0x33F00000 /* 63 MB in DRAM */ ++ ++#define CONFIG_SYS_LOAD_ADDR 0x33000000 /* default load address */ ++ ++#define CONFIG_SYS_HZ 1000 ++ ++/* valid baudrates */ ++#define CONFIG_SYS_BAUDRATE_TABLE { 9600, 19200, 38400, 57600, 115200 } ++ ++/*----------------------------------------------------------------------- ++ * Stack sizes ++ * ++ * The stack sizes are set up in start.S using the settings below ++ */ ++#define CONFIG_STACKSIZE (128*1024) /* regular stack */ ++#ifdef CONFIG_USE_IRQ ++#define CONFIG_STACKSIZE_IRQ (4*1024) /* IRQ stack */ ++#define CONFIG_STACKSIZE_FIQ (4*1024) /* FIQ stack */ ++#endif ++ ++/*----------------------------------------------------------------------- ++ * Physical Memory Map ++ */ ++#define CONFIG_NR_DRAM_BANKS 1 /* we have 1 bank of DRAM */ ++#define PHYS_SDRAM_1 0x30000000 /* SDRAM Bank #1 */ ++#define PHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */ ++ ++#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */ ++ ++#define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1 ++ ++/*----------------------------------------------------------------------- ++ * FLASH and environment organization ++ */ ++ ++#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ ++#if 0 ++#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ ++#endif ++ ++#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */ ++#ifdef CONFIG_AMD_LV800 ++#define PHYS_FLASH_SIZE 0x00100000 /* 1MB */ ++#define CONFIG_SYS_MAX_FLASH_SECT (19) /* max number of sectors on one chip */ ++#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x0F0000) /* addr of environment */ ++#endif ++#ifdef CONFIG_AMD_LV400 ++#define PHYS_FLASH_SIZE 0x00080000 /* 512KB */ ++#define CONFIG_SYS_MAX_FLASH_SECT (11) /* max number of sectors on one chip */ ++#define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x070000) /* addr of environment */ ++#endif ++ ++/* timeout values are in ticks */ ++#define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */ ++#define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */ ++ ++#define CONFIG_ENV_IS_IN_FLASH 1 ++#define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ ++ ++#endif /* __CONFIG_H */ +diff -Nuar u-boot-2010.09/include/serial.h u-boot-2010.09-1-basic/include/serial.h +--- u-boot-2010.09/include/serial.h 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/include/serial.h 2015-11-16 13:12:09.992998611 +0800 +@@ -46,7 +46,7 @@ + extern struct serial_device serial6_device; + #endif + +-#if defined(CONFIG_S3C2410) ++#if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) + extern struct serial_device s3c24xx_serial0_device; + extern struct serial_device s3c24xx_serial1_device; + extern struct serial_device s3c24xx_serial2_device; +diff -Nuar u-boot-2010.09/Makefile u-boot-2010.09-1-basic/Makefile +--- u-boot-2010.09/Makefile 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-1-basic/Makefile 2015-11-16 13:12:09.993998586 +0800 +@@ -154,6 +154,7 @@ + # load ARCH, BOARD, and CPU configuration + include $(obj)include/config.mk + export ARCH CPU BOARD VENDOR SOC ++CROSS_COMPILE= /opt/buildroot-2012.08/arm920t/usr/bin/arm-linux- + + # set default to nothing for native builds + ifeq ($(HOSTARCH),$(ARCH)) +@@ -317,6 +318,7 @@ + + $(obj)u-boot.bin: $(obj)u-boot + $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ ++ mv u-boot.bin u-boot-s3c2440.bin + + $(obj)u-boot.ldr: $(obj)u-boot + $(CREATE_LDR_ENV) diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch new file mode 100644 index 0000000..5f2b2b0 --- /dev/null +++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-2-dm9000.patch @@ -0,0 +1,70 @@ +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-2-dm9000/board/lingyun/fl2440/fl2440.c +--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c 2015-11-16 13:36:18.438996129 +0800 ++++ u-boot-2010.09-2-dm9000/board/lingyun/fl2440/fl2440.c 2015-11-16 13:35:08.196993893 +0800 +@@ -166,6 +166,9 @@ + #ifdef CONFIG_CS8900 + rc = cs8900_initialize(0, CONFIG_CS8900_BASE); + #endif ++#ifdef CONFIG_DRIVER_DM9000 ++ rc = dm9000_initialize(bis); ++#endif + return rc; + } + #endif +diff -Nuar u-boot-2010.09/drivers/net/dm9000x.c u-boot-2010.09-2-dm9000/drivers/net/dm9000x.c +--- u-boot-2010.09/drivers/net/dm9000x.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-2-dm9000/drivers/net/dm9000x.c 2015-11-16 13:35:08.199994163 +0800 +@@ -364,7 +364,7 @@ + while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */ + udelay(1000); + i++; +- if (i == 10000) { ++ if (i == 2000) { /* Modify by guowenxue */ + printf("could not establish link\n"); + return 0; + } +diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-2-dm9000/include/configs/fl2440.h +--- u-boot-2010.09/include/configs/fl2440.h 2015-11-16 13:36:18.441996228 +0800 ++++ u-boot-2010.09-2-dm9000/include/configs/fl2440.h 2015-11-16 13:35:08.199994163 +0800 +@@ -58,10 +58,15 @@ + /* + * Hardware drivers + */ +-#define CONFIG_NET_MULTI +-#define CONFIG_CS8900 /* we have a CS8900 on-board */ +-#define CONFIG_CS8900_BASE 0x19000300 +-#define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */ ++#define CONFIG_NET_MULTI 1 ++#define CONFIG_NET_RETRY_COUNT 20 ++#define CONFIG_DRIVER_DM9000 1 ++#define CONFIG_DM9000_BASE 0x20000300 /* nGCS4 */ ++#define DM9000_IO CONFIG_DM9000_BASE ++#define DM9000_DATA (CONFIG_DM9000_BASE+4) ++#define CONFIG_DM9000_USE_16BIT 1 ++#define CONFIG_DM9000_NO_SROM 1 ++#undef CONFIG_DM9000_DEBUG + + /* + * select serial console configuration +@@ -97,16 +102,14 @@ + #define CONFIG_CMD_CACHE + #define CONFIG_CMD_DATE + #define CONFIG_CMD_ELF ++#define CONFIG_CMD_PING + + + #define CONFIG_BOOTDELAY 2 +-/*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" */ +-/*#define CONFIG_ETHADDR 08:00:3e:26:0a:5b */ +-#define CONFIG_NETMASK 255.255.255.0 +-#define CONFIG_IPADDR 10.0.0.110 +-#define CONFIG_SERVERIP 10.0.0.1 +-/*#define CONFIG_BOOTFILE "elinos-lart" */ +-/*#define CONFIG_BOOTCOMMAND "tftp; bootm" */ ++#define CONFIG_ETHADDR 08:00:3e:26:0a:5b ++#define CONFIG_NETMASK 255.255.255.0 ++#define CONFIG_IPADDR 192.168.1.168 ++#define CONFIG_SERVERIP 192.168.1.2 + + #if defined(CONFIG_CMD_KGDB) + #define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch new file mode 100644 index 0000000..e2d6a20 --- /dev/null +++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-3-nand.patch @@ -0,0 +1,190 @@ +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/Makefile u-boot-2010.09-3-nand/board/lingyun/fl2440/Makefile +--- u-boot-2010.09/board/lingyun/fl2440/Makefile 2015-11-16 13:35:08.197993985 +0800 ++++ u-boot-2010.09-3-nand/board/lingyun/fl2440/Makefile 2015-11-16 13:37:57.298995667 +0800 +@@ -25,7 +25,7 @@ + + LIB = $(obj)lib$(BOARD).a + +-COBJS := fl2440.o nand_read.o flash.o ++COBJS := fl2440.o nand_read.o + SOBJS := lowlevel_init.o + + SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +diff -Nuar u-boot-2010.09/common/cmd_nand.c u-boot-2010.09-3-nand/common/cmd_nand.c +--- u-boot-2010.09/common/cmd_nand.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-3-nand/common/cmd_nand.c 2015-11-16 13:37:57.298995667 +0800 +@@ -148,6 +148,11 @@ + #if defined(CONFIG_CMD_MTDPARTS) + out: + #endif ++ /* If the size is not aligment, then let it's page alignment */ ++ if(0 != (*size%nand->writesize)) ++ { ++ *size = (*size / nand->writesize + 1) * nand->writesize; ++ } + printf("device %d ", idx); + if (*size == nand->size) + puts("whole chip\n"); +diff -Nuar u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c u-boot-2010.09-3-nand/drivers/mtd/nand/s3c2410_nand.c +--- u-boot-2010.09/drivers/mtd/nand/s3c2410_nand.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-3-nand/drivers/mtd/nand/s3c2410_nand.c 2015-11-16 13:37:57.298995667 +0800 +@@ -24,6 +24,7 @@ + #include <asm/arch/s3c24x0_cpu.h> + #include <asm/io.h> + ++#if defined(CONFIG_S3C2410) + #define S3C2410_NFCONF_EN (1<<15) + #define S3C2410_NFCONF_512BYTE (1<<14) + #define S3C2410_NFCONF_4STEP (1<<13) +@@ -36,6 +37,20 @@ + #define S3C2410_ADDR_NALE 4 + #define S3C2410_ADDR_NCLE 8 + ++#elif defined(CONFIG_S3C2440) ++#define S3C2410_NFCONT_EN (1<<0) ++#define S3C2410_NFCONT_INITECC (1<<4) ++#define S3C2410_NFCONT_nFCE (1<<1) ++#define S3C2410_NFCONT_MAINECCLOCK (1<<5) ++#define S3C2410_NFCONF_TACLS(x) ((x)<<12) ++#define S3C2410_NFCONF_TWRPH0(x) ((x)<<8) ++#define S3C2410_NFCONF_TWRPH1(x) ((x)<<4) ++ ++#define S3C2410_ADDR_NALE 0x08 ++#define S3C2410_ADDR_NCLE 0x0c ++#endif ++ulong IO_ADDR_W = CONFIG_SYS_NAND_BASE; ++ + #ifdef CONFIG_NAND_SPL + + /* in the early stage of NAND flash booting, printf() is not available */ +@@ -59,25 +74,31 @@ + debugX(1, "hwcontrol(): 0x%02x 0x%02x\n", cmd, ctrl); + + if (ctrl & NAND_CTRL_CHANGE) { +- ulong IO_ADDR_W = (ulong)nand; ++ IO_ADDR_W = (ulong)nand; + + if (!(ctrl & NAND_CLE)) + IO_ADDR_W |= S3C2410_ADDR_NCLE; + if (!(ctrl & NAND_ALE)) + IO_ADDR_W |= S3C2410_ADDR_NALE; + +- chip->IO_ADDR_W = (void *)IO_ADDR_W; ++ //chip->IO_ADDR_W = (void *)IO_ADDR_W; + + if (ctrl & NAND_NCE) +- writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, +- &nand->NFCONF); ++#if defined(CONFIG_S3C2410) ++ writel(readl(&nand->NFCONF) & ~S3C2410_NFCONF_nFCE, &nand->NFCONF); ++#elif defined(CONFIG_S3C2440) ++ writel(readl(&nand->NFCONT) & ~S3C2410_NFCONT_nFCE, &nand->NFCONT); ++#endif + else +- writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, +- &nand->NFCONF); ++#if defined(CONFIG_S3C2410) ++ writel(readl(&nand->NFCONF) | S3C2410_NFCONF_nFCE, &nand->NFCONF); ++#elif defined(CONFIG_S3C2440) ++ writel(readl(&nand->NFCONT) | S3C2410_NFCONT_nFCE, &nand->NFCONT); ++#endif + } + + if (cmd != NAND_CMD_NONE) +- writeb(cmd, chip->IO_ADDR_W); ++ writeb(cmd, (void *)IO_ADDR_W); + } + + static int s3c2410_dev_ready(struct mtd_info *mtd) +@@ -92,7 +113,11 @@ + { + struct s3c2410_nand *nand = s3c2410_get_base_nand(); + debugX(1, "s3c2410_nand_enable_hwecc(%p, %d)\n", mtd, mode); ++#if defined(CONFIG_S3C2410) + writel(readl(&nand->NFCONF) | S3C2410_NFCONF_INITECC, &nand->NFCONF); ++#elif defined(CONFIG_S3C2440) ++ writel(readl(&nand->NFCONT) | S3C2410_NFCONT_INITECC, &nand->NFCONT); ++#endif + } + + static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, +@@ -132,6 +157,7 @@ + + writel(readl(&clk_power->CLKCON) | (1 << 4), &clk_power->CLKCON); + ++#if defined(CONFIG_S3C2410) + /* initialize hardware */ + twrph0 = 3; + twrph1 = 0; +@@ -145,6 +171,20 @@ + + /* initialize nand_chip data structure */ + nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; ++#elif defined(CONFIG_S3C2440) ++ twrph0 = 4; ++ twrph1 = 2; ++ tacls = 0; ++ cfg = 0; ++ cfg |= S3C2410_NFCONF_TACLS(tacls - 1); ++ cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1); ++ cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1); ++ writel(cfg, &nand_reg->NFCONF); ++ cfg = (0<<13)|(0<<12)|(0<<10)|(0<<9)|(0<<8)|(0<<6)|(0<<5)|(1<<4)|(0<<1)|(1<<0); ++ writel(cfg, &nand_reg->NFCONT); ++ /* initialize nand_chip data structure */ ++ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)&nand_reg->NFDATA; ++#endif + + nand->select_chip = NULL; + +diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-3-nand/include/configs/fl2440.h +--- u-boot-2010.09/include/configs/fl2440.h 2015-11-16 13:35:08.199994163 +0800 ++++ u-boot-2010.09-3-nand/include/configs/fl2440.h 2015-11-16 13:37:57.298995667 +0800 +@@ -103,6 +103,7 @@ + #define CONFIG_CMD_DATE + #define CONFIG_CMD_ELF + #define CONFIG_CMD_PING ++#define CONFIG_CMD_NAND + + + #define CONFIG_BOOTDELAY 2 +@@ -159,11 +160,15 @@ + + #define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1 + ++#define CONFIG_SYS_NO_FLASH 1 ++#undef CONFIG_CMD_IMLS ++ + /*----------------------------------------------------------------------- + * FLASH and environment organization + */ +- ++#ifndef CONFIG_SYS_NO_FLASH + #define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */ ++#endif + #if 0 + #define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */ + #endif +@@ -184,7 +189,22 @@ + #define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */ + #define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */ + ++#ifndef CONFIG_SYS_NO_FLASH + #define CONFIG_ENV_IS_IN_FLASH 1 + #define CONFIG_ENV_SIZE 0x10000 /* Total Size of Environment Sector */ ++#endif ++ ++#if defined(CONFIG_CMD_NAND) ++#define CONFIG_NAND_S3C2410 ++#define CONFIG_S3C2410_NAND_SKIP_BAD 1 ++#define CONFIG_SYS_NAND_BASE 0x4E000000 ++#define CONFIG_SYS_MAX_NAND_DEVICE 1 /* Max number of NAND devices */ ++#define CONFIG_SYS_NAND_MAX_CHIPS 1 ++#define CONFIG_MTD_NAND_VERIFY_WRITE ++ ++#define CONFIG_ENV_IS_IN_NAND 1 ++#define CONFIG_ENV_OFFSET 0X60000 ++#define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ ++#endif /* CONFIG_CMD_NAND */ + + #endif /* __CONFIG_H */ diff --git a/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch new file mode 100644 index 0000000..c635445 --- /dev/null +++ b/linux-bsp/patches/u-boot-serial-patch/u-boot-2010.09-4-linux.patch @@ -0,0 +1,91 @@ +diff -Nuar u-boot-2010.09/board/lingyun/fl2440/fl2440.c u-boot-2010.09-4-linux/board/lingyun/fl2440/fl2440.c +--- u-boot-2010.09/board/lingyun/fl2440/fl2440.c 2015-11-16 13:35:08.196993893 +0800 ++++ u-boot-2010.09-4-linux/board/lingyun/fl2440/fl2440.c 2015-11-16 13:42:01.101997521 +0800 +@@ -132,8 +132,8 @@ + gpio->GPHCON = 0x002AFAAA; + gpio->GPHUP = 0x000007FF; + +- /* arch number of SMDK2410-Board */ +- gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; ++ /* arch number of MINI2440-Board */ ++ gd->bd->bi_arch_number = MACH_TYPE_MINI2440; /* Modify by guowenxue */ + + /* adress of boot parameters */ + gd->bd->bi_boot_params = 0x30000100; +diff -Nuar u-boot-2010.09/common/env_common.c u-boot-2010.09-4-linux/common/env_common.c +--- u-boot-2010.09/common/env_common.c 2010-09-29 05:20:55.000000000 +0800 ++++ u-boot-2010.09-4-linux/common/env_common.c 2015-11-16 13:53:40.179995044 +0800 +@@ -59,6 +59,30 @@ + #ifdef CONFIG_BOOTCOMMAND + "bootcmd=" CONFIG_BOOTCOMMAND "\0" + #endif ++#ifdef CONFIG_BBL_COMMAND /* Add by guowenxue, burn u-boot image */ ++ "bbl=" CONFIG_BBL_COMMAND "\0" ++#endif ++#ifdef CONFIG_BLX_COMMAND /* Add by guowenxue, burn linux kernel image */ ++ "blx=" CONFIG_BLX_COMMAND "\0" ++#endif ++#ifdef CONFIG_BARGS_INITRAMFS /* Add by guowenxue, bootargs for initramfs rootfs */ ++ "bargs_initramfs=" CONFIG_BARGS_INITRAMFS "\0" ++#endif ++#ifdef CONFIG_BURN_UBIFS /* Add by guowenxue, burn UBIFS root filesystem image */ ++ "bubifs=" CONFIG_BURN_UBIFS "\0" ++#endif ++#ifdef CONFIG_BARGS_UBIFS /* Add by guowenxue, bootargs for ubifs rootfs */ ++ "bargs_ubifs=" CONFIG_BARGS_UBIFS "\0" ++#endif ++#ifdef CONFIG_BURN_JFFS2 /* Add by guowenxue, burn JFFS2 root filesystem image */ ++ "bjffs2=" CONFIG_BURN_JFFS2 "\0" ++#endif ++#ifdef CONFIG_BARGS_JFFS2 /* Add by guowenxue, bootargs for jffs2 rootfs */ ++ "bargs_jffs2=" CONFIG_BARGS_JFFS2 "\0" ++#endif ++#ifdef CONFIG_TFTPBOOT_COMMAND /* Add by guowenxue, tftp boot linux system */ ++ "tb=" CONFIG_TFTPBOOT_COMMAND "\0" ++#endif + #ifdef CONFIG_RAMBOOTCOMMAND + "ramboot=" CONFIG_RAMBOOTCOMMAND "\0" + #endif +diff -Nuar u-boot-2010.09/include/configs/fl2440.h u-boot-2010.09-4-linux/include/configs/fl2440.h +--- u-boot-2010.09/include/configs/fl2440.h 2015-11-16 13:37:57.298995667 +0800 ++++ u-boot-2010.09-4-linux/include/configs/fl2440.h 2015-11-16 13:59:13.913995331 +0800 +@@ -112,6 +112,20 @@ + #define CONFIG_IPADDR 192.168.1.168 + #define CONFIG_SERVERIP 192.168.1.2 + ++ ++#define CONFIG_BBL_COMMAND "tftp 30008000 u-boot-s3c2440.bin;nand erase 0 100000;nand write 30008000 0 60000" ++#define CONFIG_BLX_COMMAND "tftp 30008000 linuxrom-s3c2440.bin;nand erase 100000 F00000;nand write 30008000 100000 D00000" ++#define CONFIG_TFTPBOOT_COMMAND "tftp 30008000 linuxrom-s3c2440.bin; bootm 30008000" ++#define CONFIG_BURN_JFFS2 "tftp 30800000 jffs2-$cpu.rootfs;nand erase 1000000 4000000;nand write 30800000 3800000 $filesize" ++#define CONFIG_BURN_UBIFS "tftp 30800000 ubifs-$cpu.rootfs;nand erase 1000000 4000000;nand write 30800000 8800000 $filesize" ++ ++ ++#define CONFIG_BARGS_INITRAMFS "console=ttyS0,115200 mem=64M rw loglevel=7" ++#define CONFIG_BARGS_JFFS2 "console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=jffs2 init=/linuxrc mem=64M rw noinitrd loglevel=7" ++#define CONFIG_BARGS_UBIFS "console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootwait rootfstype=ubifs init=/linuxrc mem=64M noinitrd rw loglevel=7" ++#define CONFIG_BOOTARGS CONFIG_BARGS_INITRAMFS ++#define CONFIG_BOOTCOMMAND "nand read 30008000 100000 D00000; bootm 30008000" ++ + #if defined(CONFIG_CMD_KGDB) + #define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ + /* what's this ? it's not used anywhere */ +@@ -207,4 +221,18 @@ + #define CONFIG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */ + #endif /* CONFIG_CMD_NAND */ + ++#define CONFIG_SETUP_MEMORY_TAGS ++#define CONFIG_INITRD_TAG ++#define CONFIG_CMDLINE_TAG ++ ++#define CONFIG_SYS_HUSH_PARSER ++#define CONFIG_SYS_PROMPT_HUSH_PS2 "> " ++ ++#define CONFIG_CMDLINE_EDITING ++#ifdef CONFIG_CMDLINE_EDITING ++#undef CONFIG_AUTO_COMPLETE ++#else ++#define CONFIG_AUTO_COMPLETE ++#endif ++ + #endif /* __CONFIG_H */ diff --git a/linux-bsp/tarballs/rootfs.tar.bz2 b/linux-bsp/tarballs/rootfs.tar.bz2 new file mode 100644 index 0000000..96de69b --- /dev/null +++ b/linux-bsp/tarballs/rootfs.tar.bz2 Binary files differ -- Gitblit v1.9.1