summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Documentation/commands.dox2
-rwxr-xr-xMAKEALL6
-rw-r--r--Makefile37
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/Makefile34
-rw-r--r--arch/arm/boards/at91rm9200ek/env/config2
-rw-r--r--arch/arm/boards/at91sam9260ek/env/config4
-rw-r--r--arch/arm/boards/at91sam9261ek/env/config4
-rw-r--r--arch/arm/boards/at91sam9263ek/env/config2
-rw-r--r--arch/arm/boards/at91sam9m10g45ek/env/config2
-rw-r--r--arch/arm/boards/at91sam9x5ek/env/config2
-rw-r--r--arch/arm/boards/chumby_falconwing/env/config2
-rw-r--r--arch/arm/boards/crystalfontz-cfa10036/cfa10036.c9
-rw-r--r--arch/arm/boards/eukrea_cpuimx25/env/bin/init_board4
-rw-r--r--arch/arm/boards/eukrea_cpuimx25/env/config14
-rw-r--r--arch/arm/boards/eukrea_cpuimx27/env/bin/init4
-rw-r--r--arch/arm/boards/eukrea_cpuimx35/env/bin/init_board4
-rw-r--r--arch/arm/boards/eukrea_cpuimx35/env/config14
-rw-r--r--arch/arm/boards/eukrea_cpuimx51/env/bin/init_board4
-rw-r--r--arch/arm/boards/eukrea_cpuimx51/env/config14
-rw-r--r--arch/arm/boards/freescale-mx28-evk/env/config12
-rw-r--r--arch/arm/boards/freescale-mx35-3-stack/env/config14
-rw-r--r--arch/arm/boards/freescale-mx53-loco/env/config16
-rw-r--r--arch/arm/boards/freescale-mx53-smd/env/config14
-rw-r--r--arch/arm/boards/freescale-mx6-arm2/board.c43
-rw-r--r--arch/arm/boards/freescale-mx6-sabrelite/board.c40
-rw-r--r--arch/arm/boards/friendlyarm-mini2440/env/config14
-rw-r--r--arch/arm/boards/guf-cupid/env/config14
-rw-r--r--arch/arm/boards/guf-neso/env/config14
-rw-r--r--arch/arm/boards/imx233-olinuxino/Makefile1
-rw-r--r--arch/arm/boards/imx233-olinuxino/config.h21
-rw-r--r--arch/arm/boards/imx233-olinuxino/env/bin/boot32
-rw-r--r--arch/arm/boards/imx233-olinuxino/env/bin/init15
-rw-r--r--arch/arm/boards/imx233-olinuxino/env/config42
-rw-r--r--arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c254
-rw-r--r--arch/arm/boards/karo-tx25/env/bin/init_board2
-rw-r--r--arch/arm/boards/karo-tx25/env/config14
-rw-r--r--arch/arm/boards/karo-tx28/env/config14
-rw-r--r--arch/arm/boards/karo-tx53/Makefile2
-rw-r--r--arch/arm/boards/karo-tx53/board.c240
-rw-r--r--arch/arm/boards/karo-tx53/config.h24
-rw-r--r--arch/arm/boards/karo-tx53/env/init/bootargs-base8
-rw-r--r--arch/arm/boards/karo-tx53/env/init/hostname8
-rw-r--r--arch/arm/boards/karo-tx53/flash_header.c147
-rw-r--r--arch/arm/boards/mioa701/env/bin/init2
-rw-r--r--arch/arm/boards/panda/env/config12
-rw-r--r--arch/arm/boards/pcm027/env/config14
-rw-r--r--arch/arm/boards/pcm037/env/config14
-rw-r--r--arch/arm/boards/pcm043/env/config14
-rw-r--r--arch/arm/boards/pcm049/board.c4
-rw-r--r--arch/arm/boards/pcm049/env/config16
-rw-r--r--arch/arm/boards/phycard-a-l1/env/config20
-rw-r--r--arch/arm/boards/phycard-a-l1/pca-a-l1.c6
-rw-r--r--arch/arm/boards/phycard-a-xl2/env/config16
-rw-r--r--arch/arm/boards/phycard-a-xl2/pca-a-xl2.c4
-rw-r--r--arch/arm/boards/phycard-i.MX27/env/config14
-rw-r--r--arch/arm/boards/phycard-i.MX27/lowlevel_init.S5
-rw-r--r--arch/arm/boards/phycard-i.MX27/pca100.c8
-rw-r--r--arch/arm/boards/qil-a9260/env/config2
-rw-r--r--arch/arm/boards/scb9328/env/config14
-rw-r--r--arch/arm/boards/tny-a926x/env/config6
-rw-r--r--arch/arm/boards/usb-a926x/env/config6
-rw-r--r--arch/arm/configs/chumbyone_defconfig2
-rw-r--r--arch/arm/configs/cupid_defconfig2
-rw-r--r--arch/arm/configs/eukrea_cpuimx25_defconfig2
-rw-r--r--arch/arm/configs/eukrea_cpuimx27_defconfig2
-rw-r--r--arch/arm/configs/eukrea_cpuimx35_defconfig2
-rw-r--r--arch/arm/configs/freescale_mx35_3stack_defconfig2
-rw-r--r--arch/arm/configs/freescale_mx51_babbage_defconfig2
-rw-r--r--arch/arm/configs/imx233-olinuxino_defconfig63
-rw-r--r--arch/arm/configs/imx28evk_defconfig2
-rw-r--r--arch/arm/configs/mioa701_defconfig2
-rw-r--r--arch/arm/configs/neso_defconfig2
-rw-r--r--arch/arm/configs/pcm027_defconfig2
-rw-r--r--arch/arm/configs/pcm038_defconfig2
-rw-r--r--arch/arm/configs/phycard_a_l1_defconfig2
-rw-r--r--arch/arm/configs/tx25stk5_defconfig2
-rw-r--r--arch/arm/configs/tx28stk5_defconfig2
-rw-r--r--arch/arm/configs/tx51stk5_defconfig2
-rw-r--r--arch/arm/configs/tx53stk5_defconfig76
-rw-r--r--arch/arm/cpu/mmu.c2
-rw-r--r--arch/arm/cpu/start-pbl.c21
-rw-r--r--arch/arm/cpu/start-reset.c3
-rw-r--r--arch/arm/cpu/start.c17
-rw-r--r--arch/arm/include/asm/barebox-arm.h2
-rw-r--r--arch/arm/lib/Makefile2
-rw-r--r--arch/arm/lib/armlinux.c2
-rw-r--r--arch/arm/lib/barebox.lds.S2
-rw-r--r--arch/arm/lib/runtime-offset.S17
-rw-r--r--arch/arm/mach-imx/Kconfig8
-rw-r--r--arch/arm/mach-imx/clocksource.c89
-rw-r--r--arch/arm/mach-imx/gpio.c113
-rw-r--r--arch/arm/mach-imx/imx1.c9
-rw-r--r--arch/arm/mach-imx/imx21.c13
-rw-r--r--arch/arm/mach-imx/imx25.c10
-rw-r--r--arch/arm/mach-imx/imx27.c15
-rw-r--r--arch/arm/mach-imx/imx31.c7
-rw-r--r--arch/arm/mach-imx/imx35.c7
-rw-r--r--arch/arm/mach-imx/imx51.c9
-rw-r--r--arch/arm/mach-imx/imx53.c16
-rw-r--r--arch/arm/mach-imx/imx6.c15
-rw-r--r--arch/arm/mach-imx/include/mach/imx1-regs.h23
-rw-r--r--arch/arm/mach-imx/include/mach/imx21-regs.h24
-rw-r--r--arch/arm/mach-imx/include/mach/imx25-regs.h27
-rw-r--r--arch/arm/mach-imx/include/mach/imx27-regs.h23
-rw-r--r--arch/arm/mach-imx/include/mach/imx31-regs.h27
-rw-r--r--arch/arm/mach-imx/include/mach/imx35-regs.h28
-rw-r--r--arch/arm/mach-imx/include/mach/imx51-regs.h19
-rw-r--r--arch/arm/mach-imx/include/mach/imx53-regs.h19
-rw-r--r--arch/arm/mach-imx/include/mach/imx6-regs.h19
-rw-r--r--arch/arm/mach-imx/iomux-v3.c4
-rw-r--r--arch/arm/mach-mxs/Kconfig7
-rw-r--r--arch/arm/mach-mxs/imx.c24
-rw-r--r--arch/arm/mach-nomadik/8815.c9
-rw-r--r--arch/arm/mach-omap/Kconfig24
-rw-r--r--arch/arm/mach-omap/gpio.c171
-rw-r--r--arch/arm/mach-omap/include/mach/emac_defs.h48
-rw-r--r--arch/arm/mach-omap/include/mach/xload.h4
-rw-r--r--arch/arm/mach-omap/omap3_clock.c14
-rw-r--r--arch/arm/mach-omap/omap3_generic.c19
-rw-r--r--arch/arm/mach-omap/omap4_generic.c19
-rw-r--r--arch/arm/mach-omap/xload.c99
-rw-r--r--arch/arm/mach-versatile/core.c7
-rw-r--r--arch/arm/pbl/zbarebox.lds.S2
-rw-r--r--arch/nios2/include/asm/dma-mapping.h14
-rw-r--r--arch/openrisc/Makefile4
-rw-r--r--arch/openrisc/lib/Makefile1
-rw-r--r--arch/openrisc/lib/ashrdi3.S59
-rw-r--r--arch/ppc/boards/pcm030/pcm030.c5
-rw-r--r--arch/ppc/mach-mpc5xxx/include/mach/fec.h14
-rw-r--r--arch/sandbox/board/Makefile1
-rw-r--r--arch/sandbox/board/console.c2
-rw-r--r--arch/sandbox/board/devices.c33
-rw-r--r--arch/sandbox/board/hostfile.c19
-rw-r--r--arch/sandbox/mach-sandbox/include/mach/linux.h3
-rw-r--r--arch/sandbox/os/common.c12
-rw-r--r--commands/Kconfig17
-rw-r--r--commands/Makefile2
-rw-r--r--commands/bmp.c221
-rw-r--r--commands/echo.c12
-rw-r--r--commands/global.c51
-rw-r--r--commands/oftree.c28
-rw-r--r--commands/splash.c133
-rw-r--r--common/Kconfig5
-rw-r--r--common/Makefile1
-rw-r--r--common/filetype.c77
-rw-r--r--common/globalvar.c10
-rw-r--r--common/image.c2
-rw-r--r--common/meminfo.c23
-rw-r--r--common/oftree.c4
-rw-r--r--common/startup.c21
-rw-r--r--defaultenv-2/base/bin/boot4
-rw-r--r--defaultenv-2/base/bin/bootargs-ip4
-rw-r--r--defaultenv-2/base/bin/bootargs-ip-barebox2
-rw-r--r--defaultenv-2/base/bin/bootargs-ip-dhcp2
-rw-r--r--defaultenv-2/base/bin/bootargs-ip-none2
-rw-r--r--defaultenv-2/base/bin/bootargs-root-disk2
-rw-r--r--defaultenv-2/base/bin/bootargs-root-ext2
-rw-r--r--defaultenv-2/base/bin/bootargs-root-initrd2
-rw-r--r--defaultenv-2/base/bin/bootargs-root-jffs22
-rw-r--r--defaultenv-2/base/bin/bootargs-root-nfs2
-rw-r--r--defaultenv-2/base/bin/bootargs-root-ubi2
-rw-r--r--defaultenv-2/base/bin/init5
-rw-r--r--defaultenv-2/base/boot/initrd2
-rw-r--r--defaultenv-2/base/data/ansi-colors4
-rw-r--r--defaultenv-2/base/network/eth01
-rw-r--r--defaultenv-2/menu/menu/mainmenu4
-rw-r--r--defaultenv/bin/boot12
-rw-r--r--defaultenv/bin/init2
-rw-r--r--defaultenv/config18
-rw-r--r--drivers/Kconfig1
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/amba/Makefile2
-rw-r--r--drivers/amba/bus.c210
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/bus.c37
-rw-r--r--drivers/base/driver.c63
-rw-r--r--drivers/base/platform.c36
-rw-r--r--drivers/eeprom/at25.c2
-rw-r--r--drivers/gpio/gpio-stmpe.c2
-rw-r--r--drivers/i2c/i2c.c30
-rw-r--r--drivers/mci/imx-esdhc.c24
-rw-r--r--drivers/mci/mci_spi.c10
-rw-r--r--drivers/mci/omap_hsmmc.c2
-rw-r--r--drivers/mfd/lp3972.c2
-rw-r--r--drivers/mfd/mc13xxx.c40
-rw-r--r--drivers/mfd/mc34704.c4
-rw-r--r--drivers/mfd/mc34708.c29
-rw-r--r--drivers/mfd/mc9sdz60.c2
-rw-r--r--drivers/mfd/stmpe-i2c.c2
-rw-r--r--drivers/mfd/twl4030.c2
-rw-r--r--drivers/mfd/twl6030.c2
-rw-r--r--drivers/mtd/mtdraw.c3
-rw-r--r--drivers/mtd/nand/nand_base.c97
-rw-r--r--drivers/mtd/nand/nand_ids.c30
-rw-r--r--drivers/net/Kconfig42
-rw-r--r--drivers/net/Makefile4
-rw-r--r--drivers/net/altera_tse.c48
-rw-r--r--drivers/net/altera_tse.h3
-rw-r--r--drivers/net/at91_ether.c49
-rw-r--r--drivers/net/davinci_emac.c618
-rw-r--r--drivers/net/davinci_emac.h289
-rw-r--r--drivers/net/designware.c62
-rw-r--r--drivers/net/dm9k.c50
-rw-r--r--drivers/net/ep93xx.c35
-rw-r--r--drivers/net/ep93xx.h2
-rw-r--r--drivers/net/fec_imx.c89
-rw-r--r--drivers/net/fec_imx.h6
-rw-r--r--drivers/net/fec_mpc5200.c58
-rw-r--r--drivers/net/fec_mpc5200.h4
-rw-r--r--drivers/net/gianfar.c61
-rw-r--r--drivers/net/gianfar.h2
-rw-r--r--drivers/net/ks8851_mll.c36
-rw-r--r--drivers/net/ksz8864rmn.c191
-rw-r--r--drivers/net/macb.c79
-rw-r--r--drivers/net/miidev.c313
-rw-r--r--drivers/net/netx_eth.c26
-rw-r--r--drivers/net/phy/Kconfig17
-rw-r--r--drivers/net/phy/Makefile2
-rw-r--r--drivers/net/phy/generic.c36
-rw-r--r--drivers/net/phy/mdio_bus.c250
-rw-r--r--drivers/net/phy/phy.c583
-rw-r--r--drivers/net/smc91111.c47
-rw-r--r--drivers/net/smc911x.c37
-rw-r--r--drivers/net/tap.c4
-rw-r--r--drivers/net/usb/Kconfig4
-rw-r--r--drivers/net/usb/asix.c29
-rw-r--r--drivers/net/usb/smsc95xx.c41
-rw-r--r--drivers/net/usb/usbnet.c11
-rw-r--r--drivers/nor/cfi_flash.c37
-rw-r--r--drivers/nor/cfi_flash.h2
-rw-r--r--drivers/nor/m25p80.c76
-rw-r--r--drivers/nor/m25p80.h2
-rw-r--r--drivers/of/Kconfig2
-rw-r--r--drivers/of/Makefile3
-rw-r--r--drivers/of/base.c802
-rw-r--r--drivers/of/gpio.c28
-rw-r--r--drivers/of/partition.c64
-rw-r--r--drivers/serial/amba-pl011.c74
-rw-r--r--drivers/serial/serial_imx.c17
-rw-r--r--drivers/spi/imx_spi.c49
-rw-r--r--drivers/spi/spi.c61
-rw-r--r--drivers/usb/core/usb.c5
-rw-r--r--drivers/video/fb.c31
-rw-r--r--fs/fat/ff.c37
-rw-r--r--fs/fs.c6
-rw-r--r--include/common.h4
-rw-r--r--include/driver.h45
-rw-r--r--include/fb.h2
-rw-r--r--include/fec.h3
-rw-r--r--include/filetype.h20
-rw-r--r--include/globalvar.h23
-rw-r--r--include/graphic_utils.h17
-rw-r--r--include/i2c/i2c.h8
-rw-r--r--include/image.h5
-rw-r--r--include/image_renderer.h85
-rw-r--r--include/linux/amba/bus.h153
-rw-r--r--include/linux/amba/serial.h29
-rw-r--r--include/linux/ethtool.h114
-rw-r--r--include/linux/mii.h421
-rw-r--r--include/linux/phy.h269
-rw-r--r--include/miidev.h73
-rw-r--r--include/net.h6
-rw-r--r--include/net/davinci_emac.h10
-rw-r--r--include/of.h113
-rw-r--r--include/spi/spi.h13
-rw-r--r--include/usb/usbnet.h5
-rw-r--r--lib/Kconfig36
-rw-r--r--lib/Makefile5
-rw-r--r--lib/bmp.c134
-rw-r--r--lib/bmp_layout.h (renamed from include/bmp_layout.h)11
-rw-r--r--lib/graphic_utils.c191
-rw-r--r--lib/image_renderer.c96
-rw-r--r--lib/libbb.c1
-rw-r--r--lib/lodepng.c5928
-rw-r--r--lib/lodepng.h1640
-rw-r--r--lib/picopng.c810
-rw-r--r--lib/picopng.h34
-rw-r--r--lib/png.c89
-rw-r--r--lib/png.h21
-rw-r--r--lib/png_lode.c90
-rw-r--r--lib/png_pico.c85
-rw-r--r--logo/LICENCE22
-rw-r--r--logo/png24/100x100/color/barebox.pngbin0 -> 22724 bytes
-rw-r--r--logo/png24/100x100/white/barebox.pngbin0 -> 12053 bytes
-rw-r--r--logo/png24/200x200/color/barebox.pngbin0 -> 71557 bytes
-rw-r--r--logo/png24/200x200/white/barebox.pngbin0 -> 31132 bytes
-rw-r--r--logo/png24/400x400/color/barebox.pngbin0 -> 217170 bytes
-rw-r--r--logo/png24/400x400/white/barebox.pngbin0 -> 78591 bytes
-rw-r--r--logo/png24/600x600/color/barebox.pngbin0 -> 406788 bytes
-rw-r--r--logo/png24/600x600/while/barebox.pngbin0 -> 137235 bytes
-rw-r--r--logo/png24/800x800/color/barebox.pngbin0 -> 627433 bytes
-rw-r--r--logo/png24/800x800/white/barebox.pngbin0 -> 210397 bytes
-rw-r--r--logo/png8/100x100/color/blackbg/barebox.pngbin0 -> 8279 bytes
-rw-r--r--logo/png8/100x100/white/blackbg/barebox.pngbin0 -> 6089 bytes
-rw-r--r--logo/png8/200x200/color/blackbg/barebox.pngbin0 -> 23616 bytes
-rw-r--r--logo/png8/200x200/white/blackbg/barebox.pngbin0 -> 14838 bytes
-rw-r--r--logo/png8/400x400/color/blackbg/barebox.pngbin0 -> 71295 bytes
-rw-r--r--logo/png8/400x400/white/blackbg/barebox.pngbin0 -> 38480 bytes
-rw-r--r--logo/png8/600x600/color/blackbg/barebox.pngbin0 -> 130709 bytes
-rw-r--r--logo/png8/600x600/while/blackbg/barebox.pngbin0 -> 68648 bytes
-rw-r--r--logo/png8/800x800/color/blackbg/barebox.pngbin0 -> 205281 bytes
-rw-r--r--logo/png8/800x800/white/blackbg/barebox.pngbin0 -> 104173 bytes
-rw-r--r--net/dhcp.c167
-rw-r--r--net/eth.c73
-rw-r--r--net/net.c18
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Kbuild.include2
-rw-r--r--scripts/Makefile2
-rwxr-xr-xscripts/genenv6
-rw-r--r--scripts/kconfig/.gitignore1
-rw-r--r--scripts/kconfig/zconf.lex.c2420
-rw-r--r--scripts/mk-am35xx-spi-image.c141
314 files changed, 17304 insertions, 4604 deletions
diff --git a/.gitignore b/.gitignore
index 4154c7397e..9af6710290 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,7 +34,9 @@ barebox.bin
barebox.srec
barebox.netx
barebox.s5p
+barebox.spi
barebox.ubl
+barebox.uimage
barebox.map
System.map
Module.symvers
diff --git a/Documentation/commands.dox b/Documentation/commands.dox
index 5ef7829aa8..d8cfa6b8f0 100644
--- a/Documentation/commands.dox
+++ b/Documentation/commands.dox
@@ -18,7 +18,6 @@ available in @a Barebox:
@li @subpage _name
@li @subpage addpart_command
@li @subpage alternate
-@li @subpage bmp_command
@li @subpage bootm_command
@li @subpage bootu
@li @subpage bootz
@@ -95,6 +94,7 @@ available in @a Barebox:
@li @subpage sh
@li @subpage sleep
@li @subpage source
+@li @subpage splash_command
@li @subpage test
@li @subpage timeout
@li @subpage true
diff --git a/MAKEALL b/MAKEALL
index 056a4d0547..c08e484cda 100755
--- a/MAKEALL
+++ b/MAKEALL
@@ -96,8 +96,10 @@ do_build_target() {
mkdir -p "${LOGDIR}/${target}"
printf "Building ${arch} ${target} \n" >&2 | tee -a "${log_report}"
- cross_compile=`eval echo '$CROSS_COMPILE_'${target}`
- cross_compile_set=`eval echo '${CROSS_COMPILE_'${target}'+set}'`
+ tmp=`echo "${target}" | tr - _`
+
+ cross_compile=`eval echo '$CROSS_COMPILE_'${tmp}`
+ cross_compile_set=`eval echo '${CROSS_COMPILE_'${tmp}'+set}'`
if [ "${cross_compile_set}" = "" ]
then
cross_compile=`eval echo '$CROSS_COMPILE_'${arch}`
diff --git a/Makefile b/Makefile
index c6264d3404..3d60927dae 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
VERSION = 2012
-PATCHLEVEL = 09
+PATCHLEVEL = 10
SUBLEVEL = 0
EXTRAVERSION =
NAME = Amissive Actinocutious Kiwi
@@ -462,12 +462,18 @@ CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)
# disable pointer signed / unsigned warnings in gcc 4.0
CFLAGS += $(call cc-option,-Wno-pointer-sign,)
-# Default kernel image to build when no specific target is given.
-# KBUILD_IMAGE may be overruled on the command line or
-# set in the environment
-# Also any assignments in arch/$(ARCH)/Makefile take precedence over
-# this default value
+# KBUILD_IMAGE: Default barebox image to build
+# Depending on the architecture, this can be either compressed or not.
+# It will also include any necessary headers to be bootable.
export KBUILD_IMAGE ?= barebox.bin
+# KBUILD_BINARY: Raw barebox binary
+# This variable is set in case the architecture prepends a header and
+# points to a binary that can be loaded directly into RAM and executed.
+export KBUILD_BINARY ?= barebox.bin
+# KBUILD_IMAGE and _BINARY may be overruled on the command line or
+# set in the environment.
+# Also any assignments in arch/$(ARCH)/Makefile take precedence over
+# the default value.
barebox-flash-image: $(KBUILD_IMAGE)
$(call if_changed,ln)
@@ -680,6 +686,22 @@ ifndef CONFIG_PBL_IMAGE
$(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
endif
+# By default the uImage load address is 2MB below CONFIG_TEXT_BASE,
+# leaving space for the compressed PBL image at 1MB below CONFIG_TEXT_BASE.
+UIMAGE_BASE ?= $(shell printf "0x%08x" $$(($(CONFIG_TEXT_BASE) - 0x200000)))
+
+# For development provide a target which makes barebox loadable by an
+# unmodified u-boot
+quiet_cmd_barebox_mkimage = MKIMAGE $@
+ cmd_barebox_mkimage = $(srctree)/scripts/mkimage -A $(ARCH) -T firmware -C none \
+ -O barebox -a $(UIMAGE_BASE) -e $(UIMAGE_BASE) \
+ -n "barebox $(KERNELRELEASE)" -d $< $@
+
+# barebox.uimage is build from the raw barebox binary, without any other
+# headers.
+barebox.uimage: $(KBUILD_BINARY) FORCE
+ $(call if_changed,barebox_mkimage)
+
ifdef CONFIG_X86
barebox.S: barebox
ifdef CONFIG_X86_HDBOOT
@@ -1009,7 +1031,8 @@ CLEAN_FILES += barebox System.map include/generated/barebox_default_env.h \
.tmp_version .tmp_barebox* barebox.bin barebox.map barebox.S \
.tmp_kallsyms* barebox_default_env* barebox.ldr \
scripts/bareboxenv-target barebox-flash-image \
- Doxyfile.version barebox.srec barebox.s5p
+ Doxyfile.version barebox.srec barebox.s5p barebox.ubl \
+ barebox.uimage barebox.spi
# Directories & files removed with 'make mrproper'
MRPROPER_DIRS += include/config include2 usr/include
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a54ad03445..7b7b0585ae 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -58,6 +58,7 @@ config ARCH_NOMADIK
config ARCH_OMAP
bool "TI OMAP"
select HAS_DEBUG_LL
+ select GPIOLIB
config ARCH_PXA
bool "Intel/Marvell PXA based"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 8e660bea2b..855043aedf 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -92,6 +92,7 @@ board-$(CONFIG_MACH_FREESCALE_MX25_3STACK) := freescale-mx25-3-stack
board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack
board-$(CONFIG_MACH_IMX21ADS) := imx21ads
board-$(CONFIG_MACH_IMX27ADS) := imx27ads
+board-$(CONFIG_MACH_IMX233_OLINUXINO) := imx233-olinuxino
board-$(CONFIG_MACH_MIOA701) := mioa701
board-$(CONFIG_MACH_MMCCPU) := mmccpu
board-$(CONFIG_MACH_NOMADIK_8815NHK) := nhk8815
@@ -141,6 +142,7 @@ board-$(CONFIG_MACH_TOSHIBA_AC100) := toshiba-ac100
board-$(CONFIG_MACH_CCMX51) := ccxmx51
board-$(CONFIG_MACH_TINY210) := friendlyarm-tiny210
board-$(CONFIG_MACH_SABRELITE) := freescale-mx6-sabrelite
+board-$(CONFIG_MACH_TX53) := karo-tx53
machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
@@ -179,7 +181,7 @@ barebox.netx: $(KBUILD_BINARY)
ifeq ($(machine-y),netx)
KBUILD_TARGET := barebox.netx
-KBUILD_BINARY := $(KBUILD_TARGET)
+KBUILD_IMAGE := barebox.netx
endif
barebox.s5p: $(KBUILD_BINARY)
@@ -187,7 +189,7 @@ barebox.s5p: $(KBUILD_BINARY)
ifeq ($(CONFIG_ARCH_S5PCxx),y)
KBUILD_TARGET := barebox.s5p
-KBUILD_BINARY := $(KBUILD_TARGET)
+KBUILD_IMAGE := barebox.s5p
endif
quiet_cmd_mlo ?= IFT $@
@@ -199,17 +201,31 @@ MLO: $(KBUILD_BINARY)
ifeq ($(CONFIG_OMAP_BUILD_IFT),y)
KBUILD_TARGET := MLO
-KBUILD_BINARY := $(KBUILD_TARGET)
+KBUILD_IMAGE := MLO
endif
-barebox.ubl: $(KBUILD_BINARY)
- @echo " UBL " $@
- $(Q)scripts/mkublheader $< > barebox.ubl
- $(Q)cat $< >> barebox.ubl
+quiet_cmd_davinci_ubl_image = UBL-IMG $@
+ cmd_davinci_ubl_image = set -e; \
+ scripts/mkublheader $< > $@; \
+ cat $< >> $@
+
+barebox.ubl: $(KBUILD_BINARY) FORCE
+ $(call if_changed,davinci_ubl_image)
ifeq ($(CONFIG_ARCH_DAVINCI),y)
KBUILD_TARGET := barebox.ubl
-KBUILD_BINARY := $(KBUILD_TARGET)
+KBUILD_IMAGE := barebox.ubl
+endif
+
+quiet_cmd_am35xx_spi_image = SPI-IMG $@
+ cmd_am35xx_spi_image = scripts/mk-am35xx-spi-image $< > $@
+
+barebox.spi: $(KBUILD_BINARY) FORCE
+ $(call if_changed,am35xx_spi_image)
+
+ifeq ($(CONFIG_OMAP_BUILD_SPI),y)
+KBUILD_TARGET := barebox.spi
+KBUILD_IMAGE := barebox.spi
endif
pbl := arch/arm/pbl
@@ -219,7 +235,7 @@ zbarebox.S zbarebox.bin zbarebox: barebox.bin
archclean:
$(MAKE) $(clean)=$(pbl)
-KBUILD_IMAGE := $(KBUILD_BINARY)
+KBUILD_IMAGE ?= $(KBUILD_BINARY)
archprepare: maketools
maketools:
diff --git a/arch/arm/boards/at91rm9200ek/env/config b/arch/arm/boards/at91rm9200ek/env/config
index 735bb107aa..a3830cb31a 100644
--- a/arch/arm/boards/at91rm9200ek/env/config
+++ b/arch/arm/boards/at91rm9200ek/env/config
@@ -3,7 +3,7 @@
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp-barebox
-dhcp_vendor_id=barebox-at91rm9200ek
+global.dhcp.vendor_id=barebox-at91rm9200ek
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
diff --git a/arch/arm/boards/at91sam9260ek/env/config b/arch/arm/boards/at91sam9260ek/env/config
index 06b9fafb81..8e88186217 100644
--- a/arch/arm/boards/at91sam9260ek/env/config
+++ b/arch/arm/boards/at91sam9260ek/env/config
@@ -6,9 +6,9 @@ ip=dhcp-barebox
if [ x$armlinux_architecture = x1099 ]
then
- dhcp_vendor_id=barebox-at91sam9260ek
+ global.dhcp.vendor_id=barebox-at91sam9260ek
else
- dhcp_vendor_id=barebox-at91sam9g20ek
+ global.dhcp.vendor_id=barebox-at91sam9g20ek
fi
# or set your networking parameters here
diff --git a/arch/arm/boards/at91sam9261ek/env/config b/arch/arm/boards/at91sam9261ek/env/config
index 820485dea8..7d855779ca 100644
--- a/arch/arm/boards/at91sam9261ek/env/config
+++ b/arch/arm/boards/at91sam9261ek/env/config
@@ -6,9 +6,9 @@ ip=dhcp-barebox
if [ x$armlinux_architecture = x848 ]
then
- dhcp_vendor_id=barebox-at91sam9261ek
+ global.dhcp.vendor_id=barebox-at91sam9261ek
else
- dhcp_vendor_id=barebox-at91sam9g10ek
+ global.dhcp.vendor_id=barebox-at91sam9g10ek
fi
# or set your networking parameters here
diff --git a/arch/arm/boards/at91sam9263ek/env/config b/arch/arm/boards/at91sam9263ek/env/config
index a09bc26080..5125020a73 100644
--- a/arch/arm/boards/at91sam9263ek/env/config
+++ b/arch/arm/boards/at91sam9263ek/env/config
@@ -3,7 +3,7 @@
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp-barebox
-dhcp_vendor_id=barebox-at91sam9263ek
+global.dhcp.vendor_id=barebox-at91sam9263ek
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
diff --git a/arch/arm/boards/at91sam9m10g45ek/env/config b/arch/arm/boards/at91sam9m10g45ek/env/config
index 37a20e93f2..54ed2cb9df 100644
--- a/arch/arm/boards/at91sam9m10g45ek/env/config
+++ b/arch/arm/boards/at91sam9m10g45ek/env/config
@@ -3,7 +3,7 @@
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp-barebox
-dhcp_vendor_id=barebox-at91sam9m10g45ek
+global.dhcp.vendor_id=barebox-at91sam9m10g45ek
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
diff --git a/arch/arm/boards/at91sam9x5ek/env/config b/arch/arm/boards/at91sam9x5ek/env/config
index dafe875664..6a985cedc5 100644
--- a/arch/arm/boards/at91sam9x5ek/env/config
+++ b/arch/arm/boards/at91sam9x5ek/env/config
@@ -3,7 +3,7 @@
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp-barebox
-dhcp_vendor_id=barebox-at91sam9x5ek
+global.dhcp.vendor_id=barebox-at91sam9x5ek
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
diff --git a/arch/arm/boards/chumby_falconwing/env/config b/arch/arm/boards/chumby_falconwing/env/config
index bf48da614d..3839b40584 100644
--- a/arch/arm/boards/chumby_falconwing/env/config
+++ b/arch/arm/boards/chumby_falconwing/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=falconwing
+global.hostname=falconwing
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
diff --git a/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c b/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c
index e454afd36c..522d2d783d 100644
--- a/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c
+++ b/arch/arm/boards/crystalfontz-cfa10036/cfa10036.c
@@ -23,6 +23,8 @@
#include <init.h>
#include <mci.h>
#include <io.h>
+#include <net.h>
+#include <sizes.h>
#include <mach/clock.h>
#include <mach/imx-regs.h>
@@ -89,16 +91,19 @@ static int cfa10036_devices_init(void)
armlinux_set_bootparams((void *)IMX_MEMORY_BASE + 0x100);
armlinux_set_architecture(MACH_TYPE_CFA10036);
- add_generic_device("mxs_mci", 0, NULL, IMX_SSP0_BASE, 0,
+ add_generic_device("mxs_mci", 0, NULL, IMX_SSP0_BASE, SZ_8K,
IORESOURCE_MEM, &mci_pdata);
+ add_generic_device("ocotp", 0, NULL, IMX_OCOTP_BASE, SZ_8K,
+ IORESOURCE_MEM, NULL);
+
return 0;
}
device_initcall(cfa10036_devices_init);
static int cfa10036_console_init(void)
{
- add_generic_device("stm_serial", 0, NULL, IMX_DBGUART_BASE, 8192,
+ add_generic_device("stm_serial", 0, NULL, IMX_DBGUART_BASE, SZ_8K,
IORESOURCE_MEM, NULL);
return 0;
diff --git a/arch/arm/boards/eukrea_cpuimx25/env/bin/init_board b/arch/arm/boards/eukrea_cpuimx25/env/bin/init_board
index ff3365d089..58e07e0403 100644
--- a/arch/arm/boards/eukrea_cpuimx25/env/bin/init_board
+++ b/arch/arm/boards/eukrea_cpuimx25/env/bin/init_board
@@ -1,11 +1,11 @@
#!/bin/sh
if [ -f /env/logo.bmp ]; then
- bmp /env/logo.bmp
+ splash /env/logo.bmp
fb0.enable=1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
- bmp /logo.bmp
+ splash /logo.bmp
fb0.enable=1
fi
diff --git a/arch/arm/boards/eukrea_cpuimx25/env/config b/arch/arm/boards/eukrea_cpuimx25/env/config
index b6bf93f58f..63a85b27eb 100644
--- a/arch/arm/boards/eukrea_cpuimx25/env/config
+++ b/arch/arm/boards/eukrea_cpuimx25/env/config
@@ -5,7 +5,7 @@ otg_mode="device"
# video : can be CMO-QVGA, URT-WVGA, DVI-VGA or DVI-SVGA
video="CMO-QVGA"
-hostname=eukrea-cpuimx25
+global.hostname=eukrea-cpuimx25
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
@@ -24,16 +24,16 @@ rootfs_loc=nand
# rootfs
rootfs_type=ubifs
-rootfsimage=$hostname/rootfs.$rootfs_type
+rootfsimage=${global.hostname}/rootfs.$rootfs_type
# kernel
-kernelimage=$hostname/uImage-${hostname}.bin
+kernelimage=${global.hostname}/uImage-${global.hostname}.bin
# barebox and it's env
-bareboximage=$hostname/barebox-${hostname}.bin
-bareboxenvimage=$hostname/bareboxenv-${hostname}.bin
+bareboximage=${global.hostname}/barebox-${global.hostname}.bin
+bareboxenvimage=${global.hostname}/bareboxenv-${global.hostname}.bin
-nfsroot="$eth0.serverip:/srv/nfs/$hostname"
+nfsroot="$eth0.serverip:/srv/nfs/${global.hostname}"
autoboot_timeout=1
@@ -42,7 +42,7 @@ bootargs="console=ttymxc0,115200 otg_mode=$otg_mode video=imxfb:$video"
nand_parts="256k(barebox)ro,128k(bareboxenv),3M(kernel),-(root)"
rootfs_mtdblock_nand=3
nand_device="mxc_nand"
-ubiroot="$hostname-rootfs"
+ubiroot="${global.hostname}-rootfs"
device_type="nand"
# set a fancy prompt (if support is compiled in)
diff --git a/arch/arm/boards/eukrea_cpuimx27/env/bin/init b/arch/arm/boards/eukrea_cpuimx27/env/bin/init
index f84ace9324..cd74974e25 100644
--- a/arch/arm/boards/eukrea_cpuimx27/env/bin/init
+++ b/arch/arm/boards/eukrea_cpuimx27/env/bin/init
@@ -17,11 +17,11 @@ if [ -e /dev/nand0 ]; then
fi
if [ -f /env/logo.bmp ]; then
- bmp /env/logo.bmp
+ splash /env/logo.bmp
fb0.enable=1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
- bmp /logo.bmp
+ splash /logo.bmp
fb0.enable=1
fi
diff --git a/arch/arm/boards/eukrea_cpuimx35/env/bin/init_board b/arch/arm/boards/eukrea_cpuimx35/env/bin/init_board
index 89fd9a90db..2a07a8425a 100644
--- a/arch/arm/boards/eukrea_cpuimx35/env/bin/init_board
+++ b/arch/arm/boards/eukrea_cpuimx35/env/bin/init_board
@@ -1,12 +1,12 @@
#!/bin/sh
if [ -f /env/logo.bmp ]; then
- bmp /env/logo.bmp
+ splash /env/logo.bmp
fb0.enable=1
gpio_set_value 1 1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
- bmp /logo.bmp
+ splash /logo.bmp
fb0.enable=1
gpio_set_value 1 1
fi
diff --git a/arch/arm/boards/eukrea_cpuimx35/env/config b/arch/arm/boards/eukrea_cpuimx35/env/config
index 01cbfe9b06..50d33a46c3 100644
--- a/arch/arm/boards/eukrea_cpuimx35/env/config
+++ b/arch/arm/boards/eukrea_cpuimx35/env/config
@@ -5,7 +5,7 @@ otg_mode="device"
# video : can be CMO-QVGA, URT-WVGA, DVI-VGA or DVI-SVGA
video="CMO-QVGA"
-hostname=eukrea-cpuimx35
+global.hostname=eukrea-cpuimx35
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
@@ -24,16 +24,16 @@ rootfs_loc=nand
# rootfs
rootfs_type=ubifs
-rootfsimage=$hostname/rootfs.$rootfs_type
+rootfsimage=${global.hostname}/rootfs.$rootfs_type
# kernel
-kernelimage=$hostname/uImage-${hostname}.bin
+kernelimage=${global.hostname}/uImage-${global.hostname}.bin
# barebox and it's env
-bareboximage=$hostname/barebox-${hostname}.bin
-bareboxenvimage=$hostname/bareboxenv-${hostname}.bin
+bareboximage=${global.hostname}/barebox-${global.hostname}.bin
+bareboxenvimage=${global.hostname}/bareboxenv-${global.hostname}.bin
-nfsroot="$eth0.serverip:/srv/nfs/$hostname"
+nfsroot="$eth0.serverip:/srv/nfs/${global.hostname}"
autoboot_timeout=1
@@ -42,7 +42,7 @@ bootargs="console=ttymxc0,115200 otg_mode=$otg_mode video=mx3fb:$video"
nand_parts="256k(barebox)ro,128k(bareboxenv),3M(kernel),-(root)"
rootfs_mtdblock_nand=3
nand_device="mxc_nand"
-ubiroot="$hostname-rootfs"
+ubiroot="${global.hostname}-rootfs"
device_type="nand"
# set a fancy prompt (if support is compiled in)
diff --git a/arch/arm/boards/eukrea_cpuimx51/env/bin/init_board b/arch/arm/boards/eukrea_cpuimx51/env/bin/init_board
index cb624e57aa..0af65822f1 100644
--- a/arch/arm/boards/eukrea_cpuimx51/env/bin/init_board
+++ b/arch/arm/boards/eukrea_cpuimx51/env/bin/init_board
@@ -1,12 +1,12 @@
#!/bin/sh
if [ -f /env/logo.bmp ]; then
- bmp /env/logo.bmp
+ splash /env/logo.bmp
fb0.enable=1
gpio_set_value 1 1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
- bmp /logo.bmp
+ splash /logo.bmp
fb0.enable=1
gpio_set_value 1 1
fi
diff --git a/arch/arm/boards/eukrea_cpuimx51/env/config b/arch/arm/boards/eukrea_cpuimx51/env/config
index 163d026158..17f8337f73 100644
--- a/arch/arm/boards/eukrea_cpuimx51/env/config
+++ b/arch/arm/boards/eukrea_cpuimx51/env/config
@@ -8,7 +8,7 @@ video="CMO-QVGA"
# screen type : can be 'tft' or 'dvi'
screen_type="tft"
-hostname=eukrea-cpuimx51
+global.hostname=eukrea-cpuimx51
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
@@ -27,16 +27,16 @@ rootfs_loc=nand
# rootfs
rootfs_type=ubifs
-rootfsimage=$hostname/rootfs.$rootfs_type
+rootfsimage=${global.hostname}/rootfs.$rootfs_type
# kernel
-kernelimage=$hostname/uImage-${hostname}.bin
+kernelimage=${global.hostname}/uImage-${global.hostname}.bin
# barebox and it's env
-bareboximage=$hostname/barebox-${hostname}.bin
-bareboxenvimage=$hostname/bareboxenv-${hostname}.bin
+bareboximage=${global.hostname}/barebox-${global.hostname}.bin
+bareboxenvimage=${global.hostname}/bareboxenv-${global.hostname}.bin
-nfsroot="$eth0.serverip:/srv/nfs/$hostname"
+nfsroot="$eth0.serverip:/srv/nfs/${global.hostname}"
autoboot_timeout=1
@@ -45,7 +45,7 @@ bootargs="console=ttymxc0,115200 otg_mode=$otg_mode video=$video screen_type=$sc
nand_parts="256k(barebox)ro,128k(bareboxenv),3M(kernel),-(root)"
rootfs_mtdblock_nand=3
nand_device="mxc_nand"
-ubiroot="$hostname-rootfs"
+ubiroot="${global.hostname}-rootfs"
device_type="nand"
# set a fancy prompt (if support is compiled in)
diff --git a/arch/arm/boards/freescale-mx28-evk/env/config b/arch/arm/boards/freescale-mx28-evk/env/config
index 3951c5bd06..4e2c90d4b1 100644
--- a/arch/arm/boards/freescale-mx28-evk/env/config
+++ b/arch/arm/boards/freescale-mx28-evk/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=mx28-evk
+global.hostname=mx28-evk
#user=
# use 'dhcp' to do dhcp in barebox and in kernel
@@ -24,21 +24,21 @@ rootfs_loc=net
rootfs_type=ext2
# where is the rootfs in case of 'rootfs_loc=disk' (linux name)
rootfs_part_linux_dev=mmcblk0p4
-rootfsimage=rootfs-${hostname}.$rootfs_type
+rootfsimage=rootfs-${global.hostname}.$rootfs_type
# where is the kernel image in case of 'kernel_loc=disk'
kernel_part=disk0.2
-kernelimage=zImage-$hostname
-bareboximage=barebox-${hostname}.bin
-bareboxenvimage=barebox-${hostname}.bin
+kernelimage=zImage-${global.hostname}
+bareboximage=barebox-${global.hostname}.bin
+bareboxenvimage=barebox-${global.hostname}.bin
if [ -n $user ]; then
bareboximage="$user"-"$bareboximage"
bareboxenvimage="$user"-"$bareboxenvimage"
kernelimage="$user"-"$kernelimage"
rootfsimage="$user"-"$rootfsimage"
- nfsroot="/home/$user/nfsroot/$hostname"
+ nfsroot="/home/$user/nfsroot/${global.hostname}"
else
nfsroot="/path/to/nfs/root"
fi
diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/config b/arch/arm/boards/freescale-mx35-3-stack/env/config
index 171ae8c9bf..122c0fcaba 100644
--- a/arch/arm/boards/freescale-mx35-3-stack/env/config
+++ b/arch/arm/boards/freescale-mx35-3-stack/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=mx35-3stack
+global.hostname=mx35-3stack
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/freescale-mx53-loco/env/config b/arch/arm/boards/freescale-mx53-loco/env/config
index bceddafa97..2ab126828b 100644
--- a/arch/arm/boards/freescale-mx53-loco/env/config
+++ b/arch/arm/boards/freescale-mx53-loco/env/config
@@ -1,13 +1,13 @@
#!/bin/sh
-hostname=loco
+global.hostname=loco
eth0.serverip=
user=
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp
-dhcp_vendor_id=barebox-mx53-loco
+global.dhcp.vendor_id=barebox-mx53-loco
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
@@ -22,16 +22,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/freescale-mx53-smd/env/config b/arch/arm/boards/freescale-mx53-smd/env/config
index d2afb291e8..d92beb9ee4 100644
--- a/arch/arm/boards/freescale-mx53-smd/env/config
+++ b/arch/arm/boards/freescale-mx53-smd/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=loco
+global.hostname=loco
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/freescale-mx6-arm2/board.c b/arch/arm/boards/freescale-mx6-arm2/board.c
index 0b7aab8044..ccc73182db 100644
--- a/arch/arm/boards/freescale-mx6-arm2/board.c
+++ b/arch/arm/boards/freescale-mx6-arm2/board.c
@@ -21,7 +21,7 @@
#include <asm/armlinux.h>
#include <generated/mach-types.h>
#include <partition.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include <asm/io.h>
#include <asm/mmu.h>
#include <mach/generic.h>
@@ -99,50 +99,39 @@ static int arm2_mem_init(void)
}
mem_initcall(arm2_mem_init);
-static struct fec_platform_data fec_info = {
- .xcv_type = RGMII,
- .phy_addr = 0,
-};
-
-static int mx6_rgmii_rework(void)
+static void mx6_rgmii_rework(struct phy_device *dev)
{
- struct mii_device *mdev;
u16 val;
- mdev = mii_open("phy0");
- if (!mdev) {
- printf("unable to open phy0\n");
- return -ENODEV;
- }
-
/* To enable AR8031 ouput a 125MHz clk from CLK_25M */
- mii_write(mdev, mdev->address, 0xd, 0x7);
- mii_write(mdev, mdev->address, 0xe, 0x8016);
- mii_write(mdev, mdev->address, 0xd, 0x4007);
+ phy_write(dev, 0xd, 0x7);
+ phy_write(dev, 0xe, 0x8016);
+ phy_write(dev, 0xd, 0x4007);
- val = mii_read(mdev, mdev->address, 0xe);
+ val = phy_read(dev, 0xe);
val &= 0xffe3;
val |= 0x18;
- mii_write(mdev, mdev->address, 0xe, val);
+ phy_write(dev, 0xe, val);
/* introduce tx clock delay */
- mii_write(mdev, mdev->address, 0x1d, 0x5);
+ phy_write(dev, 0x1d, 0x5);
- val = mii_read(mdev, mdev->address, 0x1e);
+ val = phy_read(dev, 0x1e);
val |= 0x0100;
- mii_write(mdev, mdev->address, 0x1e, val);
-
- mii_close(mdev);
-
- return 0;
+ phy_write(dev, 0x1e, val);
}
+static struct fec_platform_data fec_info = {
+ .xcv_type = RGMII,
+ .phy_init = mx6_rgmii_rework,
+ .phy_addr = 0,
+};
+
static int arm2_devices_init(void)
{
imx6_add_mmc3(NULL);
imx6_add_fec(&fec_info);
- mx6_rgmii_rework();
armlinux_set_bootparams((void *)0x10000100);
armlinux_set_architecture(3837);
diff --git a/arch/arm/boards/freescale-mx6-sabrelite/board.c b/arch/arm/boards/freescale-mx6-sabrelite/board.c
index 2d3c5d243b..25402d7c9c 100644
--- a/arch/arm/boards/freescale-mx6-sabrelite/board.c
+++ b/arch/arm/boards/freescale-mx6-sabrelite/board.c
@@ -23,7 +23,7 @@
#include <asm/armlinux.h>
#include <generated/mach-types.h>
#include <partition.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include <asm/io.h>
#include <asm/mmu.h>
#include <mach/generic.h>
@@ -131,38 +131,27 @@ static int sabrelite_mem_init(void)
}
mem_initcall(sabrelite_mem_init);
-static struct fec_platform_data fec_info = {
- .xcv_type = RGMII,
- .phy_addr = 6,
-};
-
-int mx6_rgmii_rework(void)
+static void mx6_rgmii_rework(struct phy_device *dev)
{
- struct mii_device *mdev;
-
- mdev = mii_open("phy0");
- if (!mdev) {
- printf("unable to open phy0\n");
- return -ENODEV;
- }
-
- mii_write(mdev, mdev->address, 0x09, 0x0f00);
+ phy_write(dev, 0x09, 0x0f00);
/* do same as linux kernel */
/* min rx data delay */
- mii_write(mdev, mdev->address, 0x0b, 0x8105);
- mii_write(mdev, mdev->address, 0x0c, 0x0000);
+ phy_write(dev, 0x0b, 0x8105);
+ phy_write(dev, 0x0c, 0x0000);
/* max rx/tx clock delay, min rx/tx control delay */
- mii_write(mdev, mdev->address, 0x0b, 0x8104);
- mii_write(mdev, mdev->address, 0x0c, 0xf0f0);
- mii_write(mdev, mdev->address, 0x0b, 0x104);
-
- mii_close(mdev);
-
- return 0;
+ phy_write(dev, 0x0b, 0x8104);
+ phy_write(dev, 0x0c, 0xf0f0);
+ phy_write(dev, 0x0b, 0x104);
}
+static struct fec_platform_data fec_info = {
+ .xcv_type = RGMII,
+ .phy_init = mx6_rgmii_rework,
+ .phy_addr = 6,
+};
+
static int sabrelite_ksz9021rn_setup(void)
{
mxc_iomux_v3_setup_multiple_pads(sabrelite_enet_pads, ARRAY_SIZE(sabrelite_enet_pads));
@@ -261,7 +250,6 @@ static int sabrelite_devices_init(void)
sabrelite_ksz9021rn_setup();
imx6_iim_register_fec_ethaddr();
imx6_add_fec(&fec_info);
- mx6_rgmii_rework();
sabrelite_ehci_init();
diff --git a/arch/arm/boards/friendlyarm-mini2440/env/config b/arch/arm/boards/friendlyarm-mini2440/env/config
index 77cc34f575..69d431a4ac 100644
--- a/arch/arm/boards/friendlyarm-mini2440/env/config
+++ b/arch/arm/boards/friendlyarm-mini2440/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=mini2440
+global.hostname=mini2440
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-${hostname}.${rootfs_type}
+rootfsimage=root-${global.hostname}.${rootfs_type}
-kernelimage=zImage-${hostname}
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="${user}"-"${kernelimage}"
- nfsroot="${eth0.serverip}:/home/${user}/nfsroot/${hostname}"
+ nfsroot="${eth0.serverip}:/home/${user}/nfsroot/${global.hostname}"
rootfsimage="${user}"-"${rootfsimage}"
else
nfsroot="${eth0.serverip}:/path/to/nfs/root"
diff --git a/arch/arm/boards/guf-cupid/env/config b/arch/arm/boards/guf-cupid/env/config
index 1be875d048..17b11a1943 100644
--- a/arch/arm/boards/guf-cupid/env/config
+++ b/arch/arm/boards/guf-cupid/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=cupid
+global.hostname=cupid
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/guf-neso/env/config b/arch/arm/boards/guf-neso/env/config
index 3013728263..1758c91454 100644
--- a/arch/arm/boards/guf-neso/env/config
+++ b/arch/arm/boards/guf-neso/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=guf-neso
+global.hostname=guf-neso
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/imx233-olinuxino/Makefile b/arch/arm/boards/imx233-olinuxino/Makefile
new file mode 100644
index 0000000000..6d71450edb
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/Makefile
@@ -0,0 +1 @@
+obj-y = imx23-olinuxino.o
diff --git a/arch/arm/boards/imx233-olinuxino/config.h b/arch/arm/boards/imx233-olinuxino/config.h
new file mode 100644
index 0000000000..87d9e2f476
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/config.h
@@ -0,0 +1,21 @@
+/*
+ * 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_
+
+#endif /* _CONFIG_H_ */
diff --git a/arch/arm/boards/imx233-olinuxino/env/bin/boot b/arch/arm/boards/imx233-olinuxino/env/bin/boot
new file mode 100644
index 0000000000..60dd93f297
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/env/bin/boot
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+. /env/config
+
+if [ x$1 = xdisk ]; then
+ rootfs_loc=disk
+ kernel_loc=disk
+elif [ x$1 = xnet ]; then
+ rootfs_loc=net
+ kernel_loc=net
+fi
+
+if [ x$ip = xdhcp ]; then
+ bootargs="$bootargs ip=dhcp"
+elif [ x$ip = xnone ]; then
+ bootargs="$bootargs ip=none"
+else
+ bootargs="$bootargs ip=$eth0.ipaddr::$eth0.gateway:$eth0.netmask:::"
+fi
+
+if [ x$rootfs_loc = xdisk ]; then
+ bootargs="$bootargs noinitrd rootfstype=$rootfs_type root=/dev/$rootfs_part"
+elif [ x$rootfs_loc = xnet ]; then
+ bootargs="$bootargs root=/dev/nfs nfsroot=$nfsroot,v3,tcp noinitrd"
+elif [ x$rootfs_loc = xinitrd ]; then
+ bootargs="$bootargs root=/dev/ram0 rdinit=/sbin/init"
+fi
+
+
+bootm -o $oftree_loc/imx23-olinuxino.dtb /dev/$kernel_part
+
+echo "Booting failed. Correct setup of 'kernel_part'?"
diff --git a/arch/arm/boards/imx233-olinuxino/env/bin/init b/arch/arm/boards/imx233-olinuxino/env/bin/init
new file mode 100644
index 0000000000..3ed68f76c5
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/env/bin/init
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+PATH=/env/bin
+export PATH
+
+. /env/config
+
+echo
+echo -n "Hit any key to stop autoboot: "
+timeout -a $autoboot_timeout
+if [ $? != 0 ]; then
+ exit
+fi
+
+boot
diff --git a/arch/arm/boards/imx233-olinuxino/env/config b/arch/arm/boards/imx233-olinuxino/env/config
new file mode 100644
index 0000000000..0e95373b19
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/env/config
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+hostname=imx23-olinuxino
+
+# use 'dhcp' to do dhcp in barebox and in kernel
+# use 'none' if you want to skip kernel ip autoconfiguration
+ip=none
+
+# or set your networking parameters here (if a USB network adapter is attached)
+#eth0.ipaddr=a.b.c.d
+#eth0.netmask=a.b.c.d
+#eth0.gateway=a.b.c.d
+#eth0.serverip=a.b.c.d
+
+# can be either 'net' or 'disk'
+kernel_loc=disk
+
+# can be either 'net', or 'disk' or 'initrd'
+rootfs_loc=disk
+
+# can be any regular filesystem like ext2, ext3, reiserfs in case of 'rootfs_loc=disk'
+rootfs_type=ext3
+
+# Where is the rootfs in case of 'rootfs_loc=disk'
+rootfs_part=mmcblk0p4
+
+# Where is the rootfs in case of 'rootfs_loc=net'
+nfsroot=FIXME
+
+# Where to get the kernel image in case of 'kernel_loc=disk'
+kernel_part=disk0.2
+
+# Where to get the device tree image in case of 'kernel_loc=disk'
+oftree_loc=env/oftree
+
+# base kernel parameter
+bootargs="console=ttyAMA0,115200 rw rootwait"
+
+autoboot_timeout=2
+
+# set a fancy prompt (if support is compiled in)
+PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m "
diff --git a/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c b/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c
new file mode 100644
index 0000000000..04826388d4
--- /dev/null
+++ b/arch/arm/boards/imx233-olinuxino/imx23-olinuxino.c
@@ -0,0 +1,254 @@
+/*
+ * (C) Copyright 2012 Fadil Berisha, <fadil.r.berisha@gmail.com>
+ * based on falconwing.c & mx23-evk.c
+ *
+ * (C) Copyright 2010 Juergen Beisert - Pengutronix
+ * (C) Copyright 2011 Wolfram Sang - Pengutronix
+ *
+ * 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 <init.h>
+#include <gpio.h>
+#include <environment.h>
+#include <errno.h>
+#include <mci.h>
+#include <asm/armlinux.h>
+#include <usb/ehci.h>
+#include <mach/usb.h>
+#include <generated/mach-types.h>
+#include <mach/imx-regs.h>
+#include <mach/clock.h>
+#include <mach/mci.h>
+
+static struct mxs_mci_platform_data mci_pdata = {
+ .caps = MMC_MODE_4BIT | MMC_MODE_HS | MMC_MODE_HS_52MHz,
+ .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, /* fixed to 3.3 V */
+ .f_min = 400000,
+};
+
+static const uint32_t pad_setup[] = {
+ /* debug port */
+ PWM1_DUART_TX | STRENGTH(S4MA), /* PWM0/DUART_TXD - U_DEBUG PIN 2 */
+ PWM0_DUART_RX | STRENGTH(S4MA), /* PWM0/DUART_RXD - U_DEBUG PIN 1 */
+
+ /* auart */
+ I2C_SDA_AUART1_RX | STRENGTH(S4MA),
+ I2C_CLK_AUART1_TX | STRENGTH(S4MA),
+
+ /* lcd */
+ LCD_D17 | STRENGTH(S12MA), /*PIN18/LCD_D17 - GPIO PIN 3 */
+ LCD_D16 | STRENGTH(S12MA),
+ LCD_D15 | STRENGTH(S12MA),
+ LCD_D14 | STRENGTH(S12MA),
+ LCD_D13 | STRENGTH(S12MA),
+ LCD_D12 | STRENGTH(S12MA),
+ LCD_D11 | STRENGTH(S12MA),
+ LCD_D10 | STRENGTH(S12MA),
+ LCD_D9 | STRENGTH(S12MA),
+ LCD_D8 | STRENGTH(S12MA),
+ LCD_D7 | STRENGTH(S12MA),
+ LCD_D6 | STRENGTH(S12MA),
+ LCD_D5 | STRENGTH(S12MA),
+ LCD_D4 | STRENGTH(S12MA),
+ LCD_D3 | STRENGTH(S12MA),
+ LCD_D2 | STRENGTH(S12MA), /* PIN3/LCD_D02 - GPIO PIN 31*/
+ LCD_D1 | STRENGTH(S12MA), /* PIN2/LCD_D01 - GPIO PIN 33*/
+ LCD_D0 | STRENGTH(S12MA), /* PIN1/LCD_D00 - GPIO PIN 35*/
+ LCD_CS, /* PIN26/LCD_CS - GPIO PIN 20*/
+ LCD_RS, /* PIN25/LCD_RS - GPIO PIN 18*/
+ LCD_WR, /* PIN24/LCD_WR - GPIO PIN 16*/
+ LCD_RESET, /* PIN23/LCD_DISP - GPIO PIN 14*/
+ LCD_ENABE | STRENGTH(S12MA), /* PIN22/LCD_EN/I2C_SCL - GPIO PIN 12*/
+ LCD_VSYNC | STRENGTH(S12MA), /* PIN21/LCD_HSYNC/I2C_SDA- GPIO PIN 10*/
+ LCD_HSYNC | STRENGTH(S12MA), /* PIN20/LCD_VSYNC - GPIO PIN 8*/
+ LCD_DOTCLOCK | STRENGTH(S12MA), /* PIN19/LCD_DOTCLK - GPIO PIN 6*/
+
+
+ /* SD card interface */
+ SSP1_DATA0 | PULLUP(1),
+ SSP1_DATA1 | PULLUP(1),
+ SSP1_DATA2 | PULLUP(1),
+ SSP1_DATA3 | PULLUP(1),
+ SSP1_SCK,
+ SSP1_CMD | PULLUP(1),
+ SSP1_DETECT | PULLUP(1),
+
+ /* led */
+ SSP1_DETECT_GPIO | GPIO_OUT | GPIO_VALUE(1),
+
+ /* gpio - USB hub LAN9512-JZX*/
+ GPMI_ALE_GPIO | GPIO_OUT | GPIO_VALUE(1),
+};
+
+static int imx23_olinuxino_mem_init(void)
+{
+ arm_add_mem_device("ram0", IMX_MEMORY_BASE, 64 * 1024 * 1024);
+
+ return 0;
+}
+mem_initcall(imx23_olinuxino_mem_init);
+
+static void olinuxino_init_usb(void)
+{
+
+ imx23_usb_phy_enable();
+
+ add_generic_usb_ehci_device(DEVICE_ID_DYNAMIC, IMX_USB_BASE, NULL);
+}
+
+/**
+ * Try to register an environment storage on the attached MCI card
+ * @return 0 on success
+ *
+ * We rely on the existence of a usable SD card, already attached to
+ * our system, to get something like a persistent memory for our environment.
+ * If this SD card is also the boot media, we can use the second partition
+ * for our environment purpose (if present!).
+ */
+static int register_persistant_environment(void)
+{
+ struct cdev *cdev;
+
+ /*
+ * The imx23-olinuxino only has one MCI card socket.
+ * So, we expect its name as "disk0".
+ */
+ cdev = cdev_by_name("disk0");
+ if (cdev == NULL) {
+ pr_err("No MCI card preset\n");
+ return -ENODEV;
+ }
+
+
+
+ /* MCI card is present, also a useable partition on it? */
+ cdev = cdev_by_name("disk0.1");
+ if (cdev == NULL) {
+ pr_err("No second partition available\n");
+ pr_info("Please create at least a second partition with"
+ " 256 kiB...512 kiB in size (your choice)\n");
+ return -ENODEV;
+ }
+
+ /* use the full partition as our persistent environment storage */
+ return devfs_add_partition("disk0.1", 0, cdev->size,
+ DEVFS_PARTITION_FIXED, "env0");
+}
+
+
+static int imx23_olinuxino_devices_init(void)
+{
+ int i, rc;
+
+
+ /* initizalize gpios */
+ for (i = 0; i < ARRAY_SIZE(pad_setup); i++)
+ imx_gpio_mode(pad_setup[i]);
+
+ armlinux_set_bootparams((void *)IMX_MEMORY_BASE + 0x100);
+ armlinux_set_architecture(MACH_TYPE_IMX233_OLINUXINO);
+
+ /* enable IOCLK to run at the PLL frequency */
+ imx_set_ioclk(480000000);
+
+ /* run the SSP unit clock at 100,000 kHz */
+ imx_set_sspclk(0, 100000000, 1);
+
+ add_generic_device("mxs_mci", DEVICE_ID_DYNAMIC, NULL, IMX_SSP1_BASE,
+ 0x8000, IORESOURCE_MEM, &mci_pdata);
+
+ olinuxino_init_usb();
+
+ rc = register_persistant_environment();
+ if (rc != 0)
+ printf("Cannot create the 'env0' persistant "
+ "environment storage (%d)\n", rc);
+
+ return 0;
+}
+
+device_initcall(imx23_olinuxino_devices_init);
+
+static int imx23_olinuxino_console_init(void)
+{
+ add_generic_device("stm_serial", 0, NULL, IMX_DBGUART_BASE, 8192,
+ IORESOURCE_MEM, NULL);
+
+ return 0;
+}
+
+console_initcall(imx23_olinuxino_console_init);
+
+/** @page olinuxino Olimex.ltd's i.MX23 evaluation kit
+
+This CPU card is based on an i.MX23 CPU. The card is shipped with:
+
+- 64 MiB synchronous dynamic RAM (mobile DDR type)
+
+
+Memory layout when @b barebox is running:
+
+- 0x40000000 start of SDRAM
+- 0x40000100 start of kernel's boot parameters
+ - below malloc area: stack area
+ - below barebox: malloc area
+- 0x42000000 start of @b barebox
+
+@section get_imx23_olinuxino_binary How to get the bootloader binary image:
+
+Using the default configuration:
+
+@verbatim
+make ARCH=arm imx23_olinuxino_defconfig
+@endverbatim
+
+Build the bootloader binary image:
+
+@verbatim
+make ARCH=arm CROSS_COMPILE=armv5compiler
+@endverbatim
+
+@note replace the armv5compiler with your ARM v5 cross compiler.
+
+@section imx233-olinuxino How to prepare an MCI card to boot
+the imx233-olinuxino with barebox
+
+- Create four primary partitions on the MCI card
+ - the first one for the bootlets (about 256 kiB)
+ - the second one for the persistant environment
+ (size is up to you, at least 256k)
+ - the third one for the kernel (2 MiB ... 4 MiB in size)
+ - the 4th one for the root filesystem which can fill the
+ rest of the available space
+
+- Mark the first partition with the partition ID "53" and copy the bootlets
+ into this partition (currently not part of @b barebox!).
+
+- @b barebox expect device tree blob file imx23-olinuxino.dtb
+ into directory env/oftree. At compile time, copy blob file into directory
+ arch/arm/boards/imx233-olinuxino/env/oftree/.
+
+- Copy the default @b barebox environment into the second partition
+ (no filesystem required).
+
+- Copy the kernel into the third partition (no filesystem required).
+
+- Create the root filesystem in the 4th partition. You may copy an
+ image into this partition or you can do it in the classic way:
+ mkfs on it, mount it and copy all required data and programs into it.
+*/
diff --git a/arch/arm/boards/karo-tx25/env/bin/init_board b/arch/arm/boards/karo-tx25/env/bin/init_board
index b17c55d445..1f35c961dc 100644
--- a/arch/arm/boards/karo-tx25/env/bin/init_board
+++ b/arch/arm/boards/karo-tx25/env/bin/init_board
@@ -1,6 +1,6 @@
if [ -e /dev/fb0 -a -e /env/splash.bmp ]; then
- bmp /env/splash.bmp
+ splash /env/splash.bmp
fb0.enable=1
fi
diff --git a/arch/arm/boards/karo-tx25/env/config b/arch/arm/boards/karo-tx25/env/config
index 28a5e7f27c..87beb6d64b 100644
--- a/arch/arm/boards/karo-tx25/env/config
+++ b/arch/arm/boards/karo-tx25/env/config
@@ -1,5 +1,5 @@
-hostname=tx25
+global.hostname=tx25
baseboard=tx28stk5
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/karo-tx28/env/config b/arch/arm/boards/karo-tx28/env/config
index b5222e99dc..52593761a7 100644
--- a/arch/arm/boards/karo-tx28/env/config
+++ b/arch/arm/boards/karo-tx28/env/config
@@ -1,7 +1,7 @@
#
#
-hostname=tx28
+global.hostname=tx28
baseboard=tx28stk5
# use 'dhcp' to do dhcp in barebox and in kernel
@@ -22,16 +22,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/karo-tx53/Makefile b/arch/arm/boards/karo-tx53/Makefile
new file mode 100644
index 0000000000..b56ce7f50d
--- /dev/null
+++ b/arch/arm/boards/karo-tx53/Makefile
@@ -0,0 +1,2 @@
+obj-y += board.o
+obj-y += flash_header.o
diff --git a/arch/arm/boards/karo-tx53/board.c b/arch/arm/boards/karo-tx53/board.c
new file mode 100644
index 0000000000..c8509bebcb
--- /dev/null
+++ b/arch/arm/boards/karo-tx53/board.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2012 Sascha Hauer, Pengutronix
+ *
+ * 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.
+ *
+ */
+#include <common.h>
+#include <environment.h>
+#include <fcntl.h>
+#include <fec.h>
+#include <fs.h>
+#include <init.h>
+#include <nand.h>
+#include <net.h>
+#include <partition.h>
+#include <sizes.h>
+
+#include <generated/mach-types.h>
+
+#include <mach/imx-regs.h>
+#include <mach/iomux-mx53.h>
+#include <mach/devices-imx53.h>
+#include <mach/generic.h>
+#include <mach/gpio.h>
+#include <mach/imx-nand.h>
+#include <mach/iim.h>
+#include <mach/imx5.h>
+
+#include <asm/armlinux.h>
+#include <io.h>
+#include <asm/mmu.h>
+
+static struct fec_platform_data fec_info = {
+ .xcv_type = RMII,
+};
+
+static iomux_v3_cfg_t tx53_pads[] = {
+ /* UART1 */
+ MX53_PAD_PATA_DIOW__UART1_TXD_MUX,
+ MX53_PAD_PATA_DMACK__UART1_RXD_MUX,
+
+ MX53_PAD_PATA_DMARQ__UART2_TXD_MUX,
+ MX53_PAD_PATA_BUFFER_EN__UART2_RXD_MUX,
+
+ MX53_PAD_PATA_CS_0__UART3_TXD_MUX,
+ MX53_PAD_PATA_CS_1__UART3_RXD_MUX,
+
+ /* setup FEC PHY pins for GPIO function */
+ MX53_PAD_FEC_REF_CLK__GPIO1_23,
+ MX53_PAD_FEC_MDC__GPIO1_31,
+ MX53_PAD_FEC_MDIO__GPIO1_22,
+ MX53_PAD_FEC_RXD0__GPIO1_27,
+ MX53_PAD_FEC_RXD1__GPIO1_26,
+ MX53_PAD_FEC_RX_ER__GPIO1_24,
+ MX53_PAD_FEC_TX_EN__GPIO1_28,
+ MX53_PAD_FEC_TXD0__GPIO1_30,
+ MX53_PAD_FEC_TXD1__GPIO1_29,
+ MX53_PAD_FEC_CRS_DV__GPIO1_25,
+
+ /* FEC PHY reset */
+ MX53_PAD_PATA_DA_0__GPIO7_6,
+ /* FEC PHY power */
+ MX53_PAD_EIM_D20__GPIO3_20,
+
+ /* SD1 */
+ MX53_PAD_SD1_CMD__ESDHC1_CMD,
+ MX53_PAD_SD1_CLK__ESDHC1_CLK,
+ MX53_PAD_SD1_DATA0__ESDHC1_DAT0,
+ MX53_PAD_SD1_DATA1__ESDHC1_DAT1,
+ MX53_PAD_SD1_DATA2__ESDHC1_DAT2,
+ MX53_PAD_SD1_DATA3__ESDHC1_DAT3,
+
+ /* SD1_CD */
+ MX53_PAD_EIM_D24__GPIO3_24,
+
+ MX53_PAD_GPIO_3__I2C3_SCL,
+ MX53_PAD_GPIO_6__I2C3_SDA,
+
+ MX53_PAD_CSI0_DAT12__IPU_CSI0_D_12,
+ MX53_PAD_CSI0_DAT13__IPU_CSI0_D_13,
+ MX53_PAD_CSI0_DAT14__IPU_CSI0_D_14,
+ MX53_PAD_CSI0_DAT15__IPU_CSI0_D_15,
+ MX53_PAD_CSI0_DAT16__IPU_CSI0_D_16,
+ MX53_PAD_CSI0_DAT17__IPU_CSI0_D_17,
+ MX53_PAD_CSI0_DAT18__IPU_CSI0_D_18,
+ MX53_PAD_CSI0_DAT19__IPU_CSI0_D_19,
+ MX53_PAD_CSI0_VSYNC__IPU_CSI0_VSYNC,
+ MX53_PAD_CSI0_MCLK__IPU_CSI0_HSYNC,
+ MX53_PAD_CSI0_PIXCLK__IPU_CSI0_PIXCLK,
+};
+
+static int tx53_mem_init(void)
+{
+ arm_add_mem_device("ram0", 0x70000000, SZ_1G);
+
+ return 0;
+}
+mem_initcall(tx53_mem_init);
+
+#define TX53_SD1_CD IMX_GPIO_NR(3, 24)
+
+static struct esdhc_platform_data tx53_sd1_data = {
+ .cd_gpio = TX53_SD1_CD,
+ .cd_type = ESDHC_CD_GPIO,
+ .wp_type = ESDHC_WP_NONE,
+};
+
+struct imx_nand_platform_data nand_info = {
+ .width = 1,
+ .hw_ecc = 1,
+ .flash_bbt = 1,
+};
+
+#define FEC_POWER_GPIO IMX_GPIO_NR(3, 20)
+#define FEC_RESET_GPIO IMX_GPIO_NR(7, 6)
+
+static struct tx53_fec_gpio_setup {
+ iomux_v3_cfg_t pad;
+ unsigned gpio:9,
+ dir:1,
+ level:1;
+} tx53_fec_gpios[] = {
+ { MX53_PAD_PATA_DA_0__GPIO7_6, FEC_RESET_GPIO, 1, 0, }, /* PHY reset */
+ { MX53_PAD_EIM_D20__GPIO3_20, FEC_POWER_GPIO, 1, 1, }, /* PHY power enable */
+ { MX53_PAD_FEC_REF_CLK__GPIO1_23, IMX_GPIO_NR(1, 23), 0, }, /* ENET_CLK */
+ { MX53_PAD_FEC_MDC__GPIO1_31, IMX_GPIO_NR(1, 31), 1, 0, }, /* MDC */
+ { MX53_PAD_FEC_MDIO__GPIO1_22, IMX_GPIO_NR(1, 22), 1, 0, }, /* MDIO */
+ { MX53_PAD_FEC_RXD0__GPIO1_27, IMX_GPIO_NR(1, 27), 1, 1, }, /* Mode0/RXD0 */
+ { MX53_PAD_FEC_RXD1__GPIO1_26, IMX_GPIO_NR(1, 26), 1, 1, }, /* Mode1/RXD1 */
+ { MX53_PAD_FEC_RX_ER__GPIO1_24, IMX_GPIO_NR(1, 24), 0, }, /* RX_ER */
+ { MX53_PAD_FEC_TX_EN__GPIO1_28, IMX_GPIO_NR(1, 28), 1, 0, }, /* TX_EN */
+ { MX53_PAD_FEC_TXD0__GPIO1_30, IMX_GPIO_NR(1, 30), 1, 0, }, /* TXD0 */
+ { MX53_PAD_FEC_TXD1__GPIO1_29, IMX_GPIO_NR(1, 29), 1, 0, }, /* TXD1 */
+ { MX53_PAD_FEC_CRS_DV__GPIO1_25, IMX_GPIO_NR(1, 25), 1, 1, }, /* Mode2/CRS_DV */
+};
+
+static iomux_v3_cfg_t tx53_fec_pads[] = {
+ MX53_PAD_FEC_REF_CLK__FEC_TX_CLK,
+ MX53_PAD_FEC_MDC__FEC_MDC,
+ MX53_PAD_FEC_MDIO__FEC_MDIO,
+ MX53_PAD_FEC_RXD0__FEC_RDATA_0,
+ MX53_PAD_FEC_RXD1__FEC_RDATA_1,
+ MX53_PAD_FEC_RX_ER__FEC_RX_ER,
+ MX53_PAD_FEC_TX_EN__FEC_TX_EN,
+ MX53_PAD_FEC_TXD0__FEC_TDATA_0,
+ MX53_PAD_FEC_TXD1__FEC_TDATA_1,
+ MX53_PAD_FEC_CRS_DV__FEC_RX_DV,
+};
+
+static inline void tx53_fec_init(void)
+{
+ int i;
+
+ /* Configure LAN8700 pads as GPIO and set up
+ * necessary strap options for PHY
+ */
+ for (i = 0; i < ARRAY_SIZE(tx53_fec_gpios); i++) {
+ struct tx53_fec_gpio_setup *gs = &tx53_fec_gpios[i];
+
+ if (gs->dir)
+ gpio_direction_output(gs->gpio, gs->level);
+ else
+ gpio_direction_input(gs->gpio);
+
+ mxc_iomux_v3_setup_pad(gs->pad);
+ }
+
+ /*
+ *Turn on phy power, leave in reset state
+ */
+ gpio_set_value(FEC_POWER_GPIO, 1);
+
+ /*
+ * Wait some time to let the phy activate the internal regulator
+ */
+ mdelay(10);
+
+ /*
+ * Deassert reset, phy latches the rest of bootstrap pins
+ */
+ gpio_set_value(FEC_RESET_GPIO, 1);
+
+ /* LAN7800 has an internal Power On Reset (POR) signal (OR'ed with
+ * the external RESET signal) which is deactivated 21ms after
+ * power on and latches the strap options.
+ * Delay for 22ms to ensure, that the internal POR is inactive
+ * before reconfiguring the strap pins.
+ */
+ mdelay(22);
+
+ /*
+ * The phy is ready, now configure imx51 pads for fec operation
+ */
+ mxc_iomux_v3_setup_multiple_pads(tx53_fec_pads,
+ ARRAY_SIZE(tx53_fec_pads));
+}
+
+static int tx53_devices_init(void)
+{
+ imx53_iim_register_fec_ethaddr();
+ tx53_fec_init();
+ imx53_add_fec(&fec_info);
+ imx53_add_mmc0(&tx53_sd1_data);
+ imx53_add_nand(&nand_info);
+
+ armlinux_set_bootparams((void *)0x70000100);
+ armlinux_set_architecture(MACH_TYPE_TX53);
+
+ return 0;
+}
+
+device_initcall(tx53_devices_init);
+
+static int tx53_part_init(void)
+{
+ devfs_add_partition("disk0", 0x00000, SZ_512K, DEVFS_PARTITION_FIXED, "self0");
+ devfs_add_partition("disk0", SZ_512K, SZ_1M, DEVFS_PARTITION_FIXED, "env0");
+
+ return 0;
+}
+late_initcall(tx53_part_init);
+
+static int tx53_console_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(tx53_pads, ARRAY_SIZE(tx53_pads));
+
+ imx53_init_lowlevel(1000);
+
+ imx53_add_uart0();
+ return 0;
+}
+console_initcall(tx53_console_init);
diff --git a/arch/arm/boards/karo-tx53/config.h b/arch/arm/boards/karo-tx53/config.h
new file mode 100644
index 0000000000..b7effe5d28
--- /dev/null
+++ b/arch/arm/boards/karo-tx53/config.h
@@ -0,0 +1,24 @@
+/**
+ * @file
+ * @brief Global defintions for the ARM i.MX51 based babbage board
+ *
+ * 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
+
+#endif /* __CONFIG_H */
diff --git a/arch/arm/boards/karo-tx53/env/init/bootargs-base b/arch/arm/boards/karo-tx53/env/init/bootargs-base
new file mode 100644
index 0000000000..d86975406e
--- /dev/null
+++ b/arch/arm/boards/karo-tx53/env/init/bootargs-base
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ "$1" = menu ]; then
+ init-menu-add-entry "$0" "Base bootargs"
+ exit
+fi
+
+global.linux.bootargs.base="console=ttymxc0,115200"
diff --git a/arch/arm/boards/karo-tx53/env/init/hostname b/arch/arm/boards/karo-tx53/env/init/hostname
new file mode 100644
index 0000000000..2de91305e5
--- /dev/null
+++ b/arch/arm/boards/karo-tx53/env/init/hostname
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+if [ "$1" = menu ]; then
+ init-menu-add-entry "$0" "hostname"
+ exit
+fi
+
+global.hostname=tx53
diff --git a/arch/arm/boards/karo-tx53/flash_header.c b/arch/arm/boards/karo-tx53/flash_header.c
new file mode 100644
index 0000000000..9b97fab2df
--- /dev/null
+++ b/arch/arm/boards/karo-tx53/flash_header.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2011 Marc Kleine-Budde <mkl@pengutronix.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.
+ *
+ * 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.
+ *
+ */
+
+#include <common.h>
+#include <asm/byteorder.h>
+#include <mach/imx-flash-header.h>
+#include <asm/barebox-arm-head.h>
+
+void __naked __flash_header_start go(void)
+{
+ barebox_arm_head();
+}
+
+/*
+ * FIXME: These are the dcd values for a Ka-Ro TX53 1011 which
+ * is not in production. It has 1GB DDR2 memory.
+ */
+struct imx_dcd_v2_entry __dcd_entry_section dcd_entry[] = {
+ { .addr = cpu_to_be32(0x53fd406c), .val = cpu_to_be32(0xffffffff), },
+ { .addr = cpu_to_be32(0x53fd4070), .val = cpu_to_be32(0xffffffff), },
+ { .addr = cpu_to_be32(0x53fd4074), .val = cpu_to_be32(0xffffffff), },
+ { .addr = cpu_to_be32(0x53fd4078), .val = cpu_to_be32(0xffffffff), },
+ { .addr = cpu_to_be32(0x53fd407c), .val = cpu_to_be32(0xffffffff), },
+ { .addr = cpu_to_be32(0x53fd4080), .val = cpu_to_be32(0xffffffff), },
+ { .addr = cpu_to_be32(0x53fd4088), .val = cpu_to_be32(0xffffffff), },
+ { .addr = cpu_to_be32(0x53fa8174), .val = cpu_to_be32(0x00000011), },
+ { .addr = cpu_to_be32(0x63fd800c), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa8554), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8560), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8594), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8584), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8558), .val = cpu_to_be32(0x00200040), },
+ { .addr = cpu_to_be32(0x53fa8568), .val = cpu_to_be32(0x00200040), },
+ { .addr = cpu_to_be32(0x53fa8590), .val = cpu_to_be32(0x00200040), },
+ { .addr = cpu_to_be32(0x53fa857c), .val = cpu_to_be32(0x00200040), },
+ { .addr = cpu_to_be32(0x53fa8564), .val = cpu_to_be32(0x00200040), },
+ { .addr = cpu_to_be32(0x53fa8580), .val = cpu_to_be32(0x00200040), },
+ { .addr = cpu_to_be32(0x53fa8570), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8578), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa872c), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8728), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa871c), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8718), .val = cpu_to_be32(0x00200000), },
+ { .addr = cpu_to_be32(0x53fa8574), .val = cpu_to_be32(0x00280000), },
+ { .addr = cpu_to_be32(0x53fa8588), .val = cpu_to_be32(0x00280000), },
+ { .addr = cpu_to_be32(0x53fa86f0), .val = cpu_to_be32(0x00280000), },
+ { .addr = cpu_to_be32(0x53fa8720), .val = cpu_to_be32(0x00280000), },
+ { .addr = cpu_to_be32(0x53fa86fc), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa86f4), .val = cpu_to_be32(0x00000200), },
+ { .addr = cpu_to_be32(0x53fa8714), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa8724), .val = cpu_to_be32(0x06000000), },
+ { .addr = cpu_to_be32(0x63fd9088), .val = cpu_to_be32(0x36353b38), },
+ { .addr = cpu_to_be32(0x63fd9090), .val = cpu_to_be32(0x49434942), },
+ { .addr = cpu_to_be32(0x63fd90f8), .val = cpu_to_be32(0x00000800), },
+ { .addr = cpu_to_be32(0x63fd907c), .val = cpu_to_be32(0x01350138), },
+ { .addr = cpu_to_be32(0x63fd9080), .val = cpu_to_be32(0x01380139), },
+ { .addr = cpu_to_be32(0x63fd9018), .val = cpu_to_be32(0x00001710), },
+ { .addr = cpu_to_be32(0x63fd9000), .val = cpu_to_be32(0x84110000), },
+ { .addr = cpu_to_be32(0x63fd900c), .val = cpu_to_be32(0x4d5122d2), },
+ { .addr = cpu_to_be32(0x63fd9010), .val = cpu_to_be32(0xb6f18a22), },
+ { .addr = cpu_to_be32(0x63fd9014), .val = cpu_to_be32(0x00c700db), },
+ { .addr = cpu_to_be32(0x63fd902c), .val = cpu_to_be32(0x000026d2), },
+ { .addr = cpu_to_be32(0x63fd9030), .val = cpu_to_be32(0x009f000e), },
+ { .addr = cpu_to_be32(0x63fd9008), .val = cpu_to_be32(0x12272000), },
+ { .addr = cpu_to_be32(0x63fd9004), .val = cpu_to_be32(0x00030012), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x04008010), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x00008020), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x00008020), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x0a528030), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x03868031), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x00068031), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x00008032), },
+ { .addr = cpu_to_be32(0x63fd9020), .val = cpu_to_be32(0x00005800), },
+ { .addr = cpu_to_be32(0x63fd9058), .val = cpu_to_be32(0x00033332), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x00448031), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x04008018), },
+ { .addr = cpu_to_be32(0x63fd901c), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x63fd9040), .val = cpu_to_be32(0x04b80003), },
+ { .addr = cpu_to_be32(0x53fa8004), .val = cpu_to_be32(0x00194005), },
+ { .addr = cpu_to_be32(0x53fa819c), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81a0), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81a4), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81a8), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81ac), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81b0), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81b4), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81b8), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81dc), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa81e0), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa8228), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa822c), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa8230), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa8234), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa8238), .val = cpu_to_be32(0x00000000), },
+ { .addr = cpu_to_be32(0x53fa84ec), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa84f0), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa84f4), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa84f8), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa84fc), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa8500), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa8504), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa8508), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa852c), .val = cpu_to_be32(0x00000004), },
+ { .addr = cpu_to_be32(0x53fa8530), .val = cpu_to_be32(0x00000004), },
+ { .addr = cpu_to_be32(0x53fa85a0), .val = cpu_to_be32(0x00000004), },
+ { .addr = cpu_to_be32(0x53fa85a4), .val = cpu_to_be32(0x00000004), },
+ { .addr = cpu_to_be32(0x53fa85a8), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa85ac), .val = cpu_to_be32(0x000000e4), },
+ { .addr = cpu_to_be32(0x53fa85b0), .val = cpu_to_be32(0x00000004), },
+};
+
+#define APP_DEST 0x70000000
+
+struct imx_flash_header_v2 __flash_header_section flash_header = {
+ .header.tag = IVT_HEADER_TAG,
+ .header.length = cpu_to_be16(32),
+ .header.version = IVT_VERSION,
+
+ .entry = APP_DEST + 0x1000,
+ .dcd_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header_v2, dcd),
+ .boot_data_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header_v2, boot_data),
+ .self = APP_DEST + 0x400,
+
+ .boot_data.start = APP_DEST,
+ .boot_data.size = DCD_BAREBOX_SIZE,
+
+ .dcd.header.tag = DCD_HEADER_TAG,
+ .dcd.header.length = cpu_to_be16(sizeof(struct imx_dcd) + sizeof(dcd_entry)),
+ .dcd.header.version = DCD_VERSION,
+
+ .dcd.command.tag = DCD_COMMAND_WRITE_TAG,
+ .dcd.command.length = cpu_to_be16(sizeof(struct imx_dcd_command) + sizeof(dcd_entry)),
+ .dcd.command.param = DCD_COMMAND_WRITE_PARAM,
+};
diff --git a/arch/arm/boards/mioa701/env/bin/init b/arch/arm/boards/mioa701/env/bin/init
index 494d0674aa..ab5d84d68b 100644
--- a/arch/arm/boards/mioa701/env/bin/init
+++ b/arch/arm/boards/mioa701/env/bin/init
@@ -12,7 +12,7 @@ led keyboard 0
sdcard_override
fb0.enable=1
-bmp /dev/mtd0.barebox-logo
+splash /dev/mtd0.barebox-logo
mtd_env_override
if [ $? = 0 ]; then
diff --git a/arch/arm/boards/panda/env/config b/arch/arm/boards/panda/env/config
index 29a63f333b..1cd7eaa352 100644
--- a/arch/arm/boards/panda/env/config
+++ b/arch/arm/boards/panda/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=panda
+global.hostname=panda
user=
# use 'dhcp' to do dhcp in barebox and in kernel
@@ -18,14 +18,14 @@ kernel_loc=tftp
# can be either 'net', 'nor', 'nand' or 'initrd'
rootfs_loc=net
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-${hostname}.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/pcm027/env/config b/arch/arm/boards/pcm027/env/config
index 3ed963c67b..ec2752a65d 100644
--- a/arch/arm/boards/pcm027/env/config
+++ b/arch/arm/boards/pcm027/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=pcm027
+global.hostname=pcm027
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/pcm037/env/config b/arch/arm/boards/pcm037/env/config
index fcdb77764c..569bfe4b68 100644
--- a/arch/arm/boards/pcm037/env/config
+++ b/arch/arm/boards/pcm037/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=pcm037
+global.hostname=pcm037
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/pcm043/env/config b/arch/arm/boards/pcm043/env/config
index 644c7fb839..491305352e 100644
--- a/arch/arm/boards/pcm043/env/config
+++ b/arch/arm/boards/pcm043/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=pcm043
+global.hostname=pcm043
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/pcm049/board.c b/arch/arm/boards/pcm049/board.c
index 91d8d4ba24..3159457f08 100644
--- a/arch/arm/boards/pcm049/board.c
+++ b/arch/arm/boards/pcm049/board.c
@@ -114,9 +114,9 @@ static int pcm049_devices_init(void)
#ifdef CONFIG_PARTITION
devfs_add_partition("nand0", 0x00000, SZ_128K, DEVFS_PARTITION_FIXED, "xload_raw");
dev_add_bb_dev("xload_raw", "xload");
- devfs_add_partition("nand0", SZ_128K, SZ_256K, DEVFS_PARTITION_FIXED, "self_raw");
+ devfs_add_partition("nand0", SZ_128K, SZ_512K, DEVFS_PARTITION_FIXED, "self_raw");
dev_add_bb_dev("self_raw", "self0");
- devfs_add_partition("nand0", SZ_128K + SZ_256K, SZ_128K, DEVFS_PARTITION_FIXED, "env_raw");
+ devfs_add_partition("nand0", SZ_128K + SZ_512K, SZ_128K, DEVFS_PARTITION_FIXED, "env_raw");
dev_add_bb_dev("env_raw", "env0");
#endif
diff --git a/arch/arm/boards/pcm049/env/config b/arch/arm/boards/pcm049/env/config
index efbe9ea038..0ae3e1bc3c 100644
--- a/arch/arm/boards/pcm049/env/config
+++ b/arch/arm/boards/pcm049/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=pcm049
+global.hostname=pcm049
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-${hostname}.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-${hostname}.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
@@ -40,7 +40,7 @@ autoboot_timeout=3
bootargs="console=ttyO2,115200"
-nand_parts="128k(xload)ro,256k(barebox),128k(bareboxenv),2M(kernel),-(root)"
+nand_parts="128k(xload)ro,512k(barebox),128k(bareboxenv),4M(kernel),-(root)"
rootfs_mtdblock_nand=4
# set a fancy prompt (if support is compiled in)
diff --git a/arch/arm/boards/phycard-a-l1/env/config b/arch/arm/boards/phycard-a-l1/env/config
index e0f4dcc2af..6de97ed5d5 100644
--- a/arch/arm/boards/phycard-a-l1/env/config
+++ b/arch/arm/boards/phycard-a-l1/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=pcaal1
+global.hostname=pcaal1
#user=
# Enter MAC address here if not retrieved automatically
@@ -26,26 +26,26 @@ rootfs_loc=nand
rootfs_type=jffs2
# where is the rootfs in case of 'rootfs_loc=disk' (linux name)
rootfs_part_linux_dev=mmcblk0p4
-rootfsimage=rootfs-${hostname}.$rootfs_type
+rootfsimage=rootfs-${global.hostname}.$rootfs_type
# where is the kernel image in case of 'kernel_loc=disk'
kernel_part=disk0.2
# The image type of the kernel. Can be uimage, zimage, raw or raw_lzo
-#kernelimage=zImage-$hostname
-kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+#kernelimage=zImage-${global.hostname}
+kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
-bareboximage=barebox-${hostname}.bin
-bareboxenvimage=barebox-${hostname}.bin
+bareboximage=barebox-${global.hostname}.bin
+bareboxenvimage=barebox-${global.hostname}.bin
if [ -n $user ]; then
bareboximage="$user"-"$bareboximage"
bareboxenvimage="$user"-"$bareboxenvimage"
kernelimage="$user"-"$kernelimage"
rootfsimage="$user"-"$rootfsimage"
- nfsroot="/home/$user/nfsroot/$hostname"
+ nfsroot="/home/$user/nfsroot/${global.hostname}"
else
nfsroot="/path/to/nfs/root"
fi
@@ -70,7 +70,7 @@ bootargs="$bootargs omapdss.def_disp=pd050vl1"
#bootargs="$bootargs omapdss.def_disp=pd104slf"
#bootargs="$bootargs omapdss.def_disp=pm070wl4"
-nand_parts="512k(x-loader)ro,1920k(barebox),128k(bareboxenv),4M(kernel),-(root)"
+nand_parts="128k(x-loader)ro,512k(barebox),128k(bareboxenv),4M(kernel),-(root)"
nand_device=omap2-nand.0
rootfs_mtdblock_nand=4
diff --git a/arch/arm/boards/phycard-a-l1/pca-a-l1.c b/arch/arm/boards/phycard-a-l1/pca-a-l1.c
index 5c2b436e5c..f2d10f2e6e 100644
--- a/arch/arm/boards/phycard-a-l1/pca-a-l1.c
+++ b/arch/arm/boards/phycard-a-l1/pca-a-l1.c
@@ -418,13 +418,13 @@ device_initcall(pcaal1_init_devices);
static int pcaal1_late_init(void)
{
#ifdef CONFIG_PARTITION
- devfs_add_partition("nand0", 0x00000, 0x80000, DEVFS_PARTITION_FIXED, "x-loader");
+ devfs_add_partition("nand0", 0x00000, SZ_128K, DEVFS_PARTITION_FIXED, "x-loader");
dev_add_bb_dev("self_raw", "x_loader0");
- devfs_add_partition("nand0", 0x80000, 0x1e0000, DEVFS_PARTITION_FIXED, "self_raw");
+ devfs_add_partition("nand0", SZ_128K, SZ_512K, DEVFS_PARTITION_FIXED, "self_raw");
dev_add_bb_dev("self_raw", "self0");
- devfs_add_partition("nand0", 0x260000, 0x20000, DEVFS_PARTITION_FIXED, "env_raw");
+ devfs_add_partition("nand0", SZ_128K + SZ_512K, SZ_128K, DEVFS_PARTITION_FIXED, "env_raw");
dev_add_bb_dev("env_raw", "env0");
#endif
return 0;
diff --git a/arch/arm/boards/phycard-a-xl2/env/config b/arch/arm/boards/phycard-a-xl2/env/config
index 59e8eb3851..349a51fb43 100644
--- a/arch/arm/boards/phycard-a-xl2/env/config
+++ b/arch/arm/boards/phycard-a-xl2/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=pcaaxl2
+global.hostname=pcaaxl2
user=
# use 'dhcp' to do dhcp in barebox and in kernel
@@ -20,16 +20,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-${hostname}.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-${hostname}.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
@@ -39,7 +39,7 @@ autoboot_timeout=3
bootargs="console=ttyO2,115200"
-nand_parts="128k(xload)ro,256k(barebox),128k(bareboxenv),4M(kernel),-(root)"
+nand_parts="128k(xload)ro,512k(barebox),128k(bareboxenv),4M(kernel),-(root)"
rootfs_mtdblock_nand=4
# set a fancy prompt (if support is compiled in)
diff --git a/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c b/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c
index 0df067929b..64e6d94ae1 100644
--- a/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c
+++ b/arch/arm/boards/phycard-a-xl2/pca-a-xl2.c
@@ -132,10 +132,10 @@ static int pcaaxl2_devices_init(void)
devfs_add_partition("nand0", 0x00000, SZ_128K,
DEVFS_PARTITION_FIXED, "xload_raw");
dev_add_bb_dev("xload_raw", "xload");
- devfs_add_partition("nand0", SZ_128K, SZ_256K,
+ devfs_add_partition("nand0", SZ_128K, SZ_512K,
DEVFS_PARTITION_FIXED, "self_raw");
dev_add_bb_dev("self_raw", "self0");
- devfs_add_partition("nand0", SZ_128K + SZ_256K, SZ_128K,
+ devfs_add_partition("nand0", SZ_128K + SZ_512K, SZ_128K,
DEVFS_PARTITION_FIXED, "env_raw");
dev_add_bb_dev("env_raw", "env0");
#endif
diff --git a/arch/arm/boards/phycard-i.MX27/env/config b/arch/arm/boards/phycard-i.MX27/env/config
index 367029bee5..5f77440196 100644
--- a/arch/arm/boards/phycard-i.MX27/env/config
+++ b/arch/arm/boards/phycard-i.MX27/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=pca100
+global.hostname=pca100
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/phycard-i.MX27/lowlevel_init.S b/arch/arm/boards/phycard-i.MX27/lowlevel_init.S
index c24edd49da..f98364267d 100644
--- a/arch/arm/boards/phycard-i.MX27/lowlevel_init.S
+++ b/arch/arm/boards/phycard-i.MX27/lowlevel_init.S
@@ -116,7 +116,10 @@ copy_loop:
ldr pc, =1f /* Jump to SDRAM */
1:
- b nand_boot /* Load barebox from NAND Flash */
+ ldr r0,=_text
+ ldr r1,=_barebox_image_size
+ bl imx_nand_load_image
+ b board_init_lowlevel_return
#endif /* CONFIG_NAND_IMX_BOOT */
diff --git a/arch/arm/boards/phycard-i.MX27/pca100.c b/arch/arm/boards/phycard-i.MX27/pca100.c
index 16f3e4fdea..77fa8a92cd 100644
--- a/arch/arm/boards/phycard-i.MX27/pca100.c
+++ b/arch/arm/boards/phycard-i.MX27/pca100.c
@@ -320,11 +320,3 @@ static int pca100_console_init(void)
}
console_initcall(pca100_console_init);
-
-#ifdef CONFIG_NAND_IMX_BOOT
-void __bare_init nand_boot(void)
-{
- imx_nand_load_image(_text, barebox_image_size);
-}
-#endif
-
diff --git a/arch/arm/boards/qil-a9260/env/config b/arch/arm/boards/qil-a9260/env/config
index c0b554625c..99711062f8 100644
--- a/arch/arm/boards/qil-a9260/env/config
+++ b/arch/arm/boards/qil-a9260/env/config
@@ -3,7 +3,7 @@
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp-barebox
-dhcp_vendor_id=barebox-qil-a9260
+global.dhcp.vendor_id=barebox-qil-a9260
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
diff --git a/arch/arm/boards/scb9328/env/config b/arch/arm/boards/scb9328/env/config
index a8eace7b24..ce6310b67d 100644
--- a/arch/arm/boards/scb9328/env/config
+++ b/arch/arm/boards/scb9328/env/config
@@ -1,6 +1,6 @@
#!/bin/sh
-hostname=scb9328
+global.hostname=scb9328
eth0.serverip=
user=
@@ -21,16 +21,16 @@ rootfs_loc=net
# can be either 'jffs2' or 'ubifs'
rootfs_type=ubifs
-rootfsimage=root-$hostname.$rootfs_type
+rootfsimage=root-${global.hostname}.$rootfs_type
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
if [ -n $user ]; then
kernelimage="$user"-"$kernelimage"
- nfsroot="$eth0.serverip:/home/$user/nfsroot/$hostname"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/${global.hostname}"
rootfsimage="$user"-"$rootfsimage"
else
nfsroot="$eth0.serverip:/path/to/nfs/root"
diff --git a/arch/arm/boards/tny-a926x/env/config b/arch/arm/boards/tny-a926x/env/config
index 514fc9f142..c19ec4fd61 100644
--- a/arch/arm/boards/tny-a926x/env/config
+++ b/arch/arm/boards/tny-a926x/env/config
@@ -3,9 +3,9 @@
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp-barebox
-[ x$armlinux_architecture = x2058 ] && dhcp_vendor_id=barebox-tny-a9260
-[ x$armlinux_architecture = x2059 ] && dhcp_vendor_id=barebox-tny-a9g20
-[ x$armlinux_architecture = x2140 ] && dhcp_vendor_id=barebox-tny-a9263
+[ x$armlinux_architecture = x2058 ] && global.dhcp.vendor_id=barebox-tny-a9260
+[ x$armlinux_architecture = x2059 ] && global.dhcp.vendor_id=barebox-tny-a9g20
+[ x$armlinux_architecture = x2140 ] && global.dhcp.vendor_id=barebox-tny-a9263
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
diff --git a/arch/arm/boards/usb-a926x/env/config b/arch/arm/boards/usb-a926x/env/config
index dc0a264056..49199ba391 100644
--- a/arch/arm/boards/usb-a926x/env/config
+++ b/arch/arm/boards/usb-a926x/env/config
@@ -3,9 +3,9 @@
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp-barebox
-[ x$armlinux_architecture = x1709 ] && dhcp_vendor_id=barebox-usb-a9260
-[ x$armlinux_architecture = x1710 ] && dhcp_vendor_id=barebox-usb-a9263
-[ x$armlinux_architecture = x1841 ] && dhcp_vendor_id=barebox-usb-a9g20
+[ x$armlinux_architecture = x1709 ] && global.dhcp.vendor_id=barebox-usb-a9260
+[ x$armlinux_architecture = x1710 ] && global.dhcp.vendor_id=barebox-usb-a9263
+[ x$armlinux_architecture = x1841 ] && global.dhcp.vendor_id=barebox-usb-a9g20
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
diff --git a/arch/arm/configs/chumbyone_defconfig b/arch/arm/configs/chumbyone_defconfig
index 33d83a87c1..1b03530c45 100644
--- a/arch/arm/configs/chumbyone_defconfig
+++ b/arch/arm/configs/chumbyone_defconfig
@@ -30,7 +30,7 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_NET=y
CONFIG_NET_DHCP=y
diff --git a/arch/arm/configs/cupid_defconfig b/arch/arm/configs/cupid_defconfig
index 28d199b8ed..d7716ea26b 100644
--- a/arch/arm/configs/cupid_defconfig
+++ b/arch/arm/configs/cupid_defconfig
@@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y
diff --git a/arch/arm/configs/eukrea_cpuimx25_defconfig b/arch/arm/configs/eukrea_cpuimx25_defconfig
index f7207e8b89..5eb4ff37a6 100644
--- a/arch/arm/configs/eukrea_cpuimx25_defconfig
+++ b/arch/arm/configs/eukrea_cpuimx25_defconfig
@@ -43,7 +43,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y
diff --git a/arch/arm/configs/eukrea_cpuimx27_defconfig b/arch/arm/configs/eukrea_cpuimx27_defconfig
index 93de428e15..2b951569fc 100644
--- a/arch/arm/configs/eukrea_cpuimx27_defconfig
+++ b/arch/arm/configs/eukrea_cpuimx27_defconfig
@@ -31,7 +31,7 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y
diff --git a/arch/arm/configs/eukrea_cpuimx35_defconfig b/arch/arm/configs/eukrea_cpuimx35_defconfig
index 880beb6f19..16ef4ccef3 100644
--- a/arch/arm/configs/eukrea_cpuimx35_defconfig
+++ b/arch/arm/configs/eukrea_cpuimx35_defconfig
@@ -44,7 +44,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y
diff --git a/arch/arm/configs/freescale_mx35_3stack_defconfig b/arch/arm/configs/freescale_mx35_3stack_defconfig
index a60658dc2f..4052325e95 100644
--- a/arch/arm/configs/freescale_mx35_3stack_defconfig
+++ b/arch/arm/configs/freescale_mx35_3stack_defconfig
@@ -42,7 +42,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y
diff --git a/arch/arm/configs/freescale_mx51_babbage_defconfig b/arch/arm/configs/freescale_mx51_babbage_defconfig
index 22ef163a4b..0817cfa957 100644
--- a/arch/arm/configs/freescale_mx51_babbage_defconfig
+++ b/arch/arm/configs/freescale_mx51_babbage_defconfig
@@ -17,6 +17,7 @@ CONFIG_CMDLINE_EDITING=y
CONFIG_AUTO_COMPLETE=y
CONFIG_MENU=y
CONFIG_DEFAULT_ENVIRONMENT_COMPRESSED_LZO=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/freescale-mx51-pdk/env/"
CONFIG_CMD_EDIT=y
CONFIG_CMD_SLEEP=y
@@ -39,7 +40,6 @@ CONFIG_CMD_BOOTM_INITRD=y
CONFIG_CMD_BOOTM_OFTREE=y
CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y
CONFIG_CMD_UIMAGE=y
-# CONFIG_CMD_BOOTZ is not set
# CONFIG_CMD_BOOTU is not set
CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
diff --git a/arch/arm/configs/imx233-olinuxino_defconfig b/arch/arm/configs/imx233-olinuxino_defconfig
new file mode 100644
index 0000000000..40b7e1df2e
--- /dev/null
+++ b/arch/arm/configs/imx233-olinuxino_defconfig
@@ -0,0 +1,63 @@
+CONFIG_ARCH_MXS=y
+CONFIG_MACH_IMX233_OLINUXINO=y
+CONFIG_AEABI=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_BROKEN=y
+CONFIG_EXPERIMENTAL=y
+CONFIG_MODULES=y
+CONFIG_LONGHELP=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_MENU=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/imx233-olinuxino/env"
+CONFIG_BAREBOXENV_TARGET=y
+CONFIG_DEBUG_INFO=y
+CONFIG_ENABLE_FLASH_NOISE=y
+CONFIG_ENABLE_PARTITION_NOISE=y
+CONFIG_ENABLE_DEVICE_NOISE=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_MTEST=y
+CONFIG_CMD_MTEST_ALTERNATIVE=y
+CONFIG_CMD_BOOTM_SHOW_TYPE=y
+CONFIG_CMD_BOOTM_VERBOSE=y
+CONFIG_CMD_BOOTM_INITRD=y
+CONFIG_CMD_BOOTM_OFTREE=y
+CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y
+CONFIG_CMD_UIMAGE=y
+CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_OFTREE=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_PARTITION=y
+CONFIG_NET=y
+CONFIG_NET_DHCP=y
+CONFIG_NET_NFS=y
+CONFIG_NET_PING=y
+CONFIG_NET_TFTP=y
+CONFIG_NET_TFTP_PUSH=y
+CONFIG_NET_NETCONSOLE=y
+CONFIG_NET_RESOLV=y
+CONFIG_NET_USB=y
+CONFIG_NET_USB_SMSC95XX=y
+CONFIG_DISK_INTF_PLATFORM_IDE=y
+CONFIG_USB=y
+CONFIG_USB_EHCI=y
+CONFIG_USB_STORAGE=y
+CONFIG_VIDEO=y
+CONFIG_DRIVER_VIDEO_STM=y
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+CONFIG_MCI_MXS=y
+CONFIG_LED=y
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_MXS_APBH_DMA=y
+CONFIG_FS_TFTP=y
+CONFIG_FS_NFS=y
+CONFIG_FS_FAT=y
diff --git a/arch/arm/configs/imx28evk_defconfig b/arch/arm/configs/imx28evk_defconfig
index 1b44cf4ecc..f4d4661918 100644
--- a/arch/arm/configs/imx28evk_defconfig
+++ b/arch/arm/configs/imx28evk_defconfig
@@ -33,7 +33,7 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_NET=y
CONFIG_NET_DHCP=y
diff --git a/arch/arm/configs/mioa701_defconfig b/arch/arm/configs/mioa701_defconfig
index 2bb3ceccbf..5f06b3c771 100644
--- a/arch/arm/configs/mioa701_defconfig
+++ b/arch/arm/configs/mioa701_defconfig
@@ -38,7 +38,7 @@ CONFIG_CMD_BOOTM_INITRD=y
CONFIG_CMD_RESET=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_LED=y
diff --git a/arch/arm/configs/neso_defconfig b/arch/arm/configs/neso_defconfig
index 5744dc1c71..3ea689195a 100644
--- a/arch/arm/configs/neso_defconfig
+++ b/arch/arm/configs/neso_defconfig
@@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y
diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig
index 9760e66065..5a65a720ba 100644
--- a/arch/arm/configs/pcm027_defconfig
+++ b/arch/arm/configs/pcm027_defconfig
@@ -43,7 +43,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y
diff --git a/arch/arm/configs/pcm038_defconfig b/arch/arm/configs/pcm038_defconfig
index 5ce4f7abcc..bab4002a6a 100644
--- a/arch/arm/configs/pcm038_defconfig
+++ b/arch/arm/configs/pcm038_defconfig
@@ -49,7 +49,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y
diff --git a/arch/arm/configs/phycard_a_l1_defconfig b/arch/arm/configs/phycard_a_l1_defconfig
index cf980f7ffb..4cf2d210c9 100644
--- a/arch/arm/configs/phycard_a_l1_defconfig
+++ b/arch/arm/configs/phycard_a_l1_defconfig
@@ -134,7 +134,7 @@ CONFIG_NET_NETCONSOLE=y
CONFIG_NET_RESOLV=y
CONFIG_DRIVER_SERIAL_NS16550=y
CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y
-CONFIG_MIIDEV=y
+CONFIG_PHYLIB=y
CONFIG_DRIVER_NET_SMC911X=y
CONFIG_DRIVER_NET_SMC911X_ADDRESS_SHIFT=0
CONFIG_SPI=n
diff --git a/arch/arm/configs/tx25stk5_defconfig b/arch/arm/configs/tx25stk5_defconfig
index 99057c2862..e098ef885b 100644
--- a/arch/arm/configs/tx25stk5_defconfig
+++ b/arch/arm/configs/tx25stk5_defconfig
@@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y
diff --git a/arch/arm/configs/tx28stk5_defconfig b/arch/arm/configs/tx28stk5_defconfig
index b4e3747801..49a0ab3c40 100644
--- a/arch/arm/configs/tx28stk5_defconfig
+++ b/arch/arm/configs/tx28stk5_defconfig
@@ -41,7 +41,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
-CONFIG_CMD_BMP=y
+CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y
diff --git a/arch/arm/configs/tx51stk5_defconfig b/arch/arm/configs/tx51stk5_defconfig
index 7fff0f0d10..2c831890c7 100644
--- a/arch/arm/configs/tx51stk5_defconfig
+++ b/arch/arm/configs/tx51stk5_defconfig
@@ -110,7 +110,7 @@ CONFIG_NET_TFTP=y
CONFIG_NET_TFTP_PUSH=y
CONFIG_DRIVER_SERIAL_IMX=y
CONFIG_ARCH_HAS_FEC_IMX=y
-CONFIG_MIIDEV=y
+CONFIG_PHYLIB=y
CONFIG_DRIVER_NET_FEC_IMX=y
CONFIG_DRIVER_SPI_IMX_2_3=y
CONFIG_MTD=y
diff --git a/arch/arm/configs/tx53stk5_defconfig b/arch/arm/configs/tx53stk5_defconfig
new file mode 100644
index 0000000000..95cf460b47
--- /dev/null
+++ b/arch/arm/configs/tx53stk5_defconfig
@@ -0,0 +1,76 @@
+CONFIG_ARCH_IMX=y
+CONFIG_ARCH_IMX53=y
+CONFIG_MACH_TX53=y
+CONFIG_IMX_IIM=y
+CONFIG_AEABI=y
+CONFIG_THUMB2_BAREBOX=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_ARM_UNWIND=y
+CONFIG_MMU=y
+CONFIG_TEXT_BASE=0x97f00000
+CONFIG_MALLOC_SIZE=0x2000000
+CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
+CONFIG_LONGHELP=y
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+CONFIG_MENU=y
+CONFIG_DEFAULT_ENVIRONMENT_COMPRESSED_LZO=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC_NEW=y
+CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/karo-tx53/env"
+CONFIG_RESET_SOURCE=y
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_MSLEEP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_MENU=y
+CONFIG_CMD_MENU_MANAGEMENT=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_DIRNAME=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_IOMEM=y
+CONFIG_CMD_CRC=y
+CONFIG_CMD_CRC_CMP=y
+CONFIG_CMD_MTEST=y
+CONFIG_CMD_MTEST_ALTERNATIVE=y
+CONFIG_CMD_FLASH=y
+CONFIG_CMD_BOOTM_SHOW_TYPE=y
+CONFIG_CMD_BOOTM_VERBOSE=y
+CONFIG_CMD_BOOTM_INITRD=y
+CONFIG_CMD_BOOTM_OFTREE=y
+CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y
+CONFIG_CMD_UIMAGE=y
+CONFIG_CMD_RESET=y
+CONFIG_CMD_GO=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_PARTITION=y
+CONFIG_CMD_MAGICVAR=y
+CONFIG_CMD_MAGICVAR_HELP=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_UNCOMPRESS=y
+CONFIG_CMD_LED=y
+CONFIG_NET=y
+CONFIG_NET_DHCP=y
+CONFIG_NET_PING=y
+CONFIG_NET_TFTP=y
+CONFIG_NET_TFTP_PUSH=y
+CONFIG_DRIVER_NET_FEC_IMX=y
+CONFIG_MTD=y
+CONFIG_NAND=y
+CONFIG_NAND_IMX=y
+CONFIG_UBI=y
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+CONFIG_MCI_IMX_ESDHC=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_FS_TFTP=y
+CONFIG_FS_NFS=y
+CONFIG_FS_FAT=y
+CONFIG_ZLIB=y
+CONFIG_LZO_DECOMPRESS=y
diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c
index dad8092e9f..e3ca722300 100644
--- a/arch/arm/cpu/mmu.c
+++ b/arch/arm/cpu/mmu.c
@@ -144,7 +144,7 @@ static int arm_mmu_remap_sdram(struct memory_bank *bank)
if ((phys & (SZ_1M - 1)) || (bank->size & (SZ_1M - 1)))
return -EINVAL;
- ptes = memalign(PAGE_SIZE, num_ptes * sizeof(u32));
+ ptes = xmemalign(PAGE_SIZE, num_ptes * sizeof(u32));
debug("ptes: 0x%p ttb_start: 0x%08lx ttb_end: 0x%08lx\n",
ptes, ttb_start, ttb_end);
diff --git a/arch/arm/cpu/start-pbl.c b/arch/arm/cpu/start-pbl.c
index 932a3da9e2..04b54304e1 100644
--- a/arch/arm/cpu/start-pbl.c
+++ b/arch/arm/cpu/start-pbl.c
@@ -36,6 +36,9 @@
unsigned long free_mem_ptr;
unsigned long free_mem_end_ptr;
+/*
+ * First instructions in the pbl image
+ */
void __naked __section(.text_head_entry) pbl_start(void)
{
barebox_arm_head();
@@ -116,7 +119,11 @@ static void mmu_disable(void)
static void barebox_uncompress(void *compressed_start, unsigned int len)
{
void (*barebox)(void);
- int use_mmu = IS_ENABLED(CONFIG_MMU);
+ /*
+ * remap_cached currently does not work rendering the feature
+ * of enabling the MMU in the PBL useless. disable for now.
+ */
+ int use_mmu = 0;
/* set 128 KiB at the end of the MALLOC_BASE for early malloc */
free_mem_ptr = MALLOC_BASE + MALLOC_SIZE - SZ_128K;
@@ -149,23 +156,17 @@ static void barebox_uncompress(void *compressed_start, unsigned int len)
* Board code can jump here by either returning from board_init_lowlevel
* or by calling this function directly.
*/
-void __naked __section(.text_ll_return) board_init_lowlevel_return(void)
+void __naked board_init_lowlevel_return(void)
{
- uint32_t r, addr, offset;
+ uint32_t r, offset;
uint32_t pg_start, pg_end, pg_len;
- /*
- * Get runtime address of this function. Do not
- * put any code above this.
- */
- __asm__ __volatile__("1: adr %0, 1b":"=r"(addr));
-
/* Setup the stack */
r = STACK_BASE + STACK_SIZE - 16;
__asm__ __volatile__("mov sp, %0" : : "r"(r));
/* Get offset between linked address and runtime address */
- offset = (uint32_t)__ll_return - addr;
+ offset = get_runtime_offset();
pg_start = (uint32_t)&input_data - offset;
pg_end = (uint32_t)&input_data_end - offset;
diff --git a/arch/arm/cpu/start-reset.c b/arch/arm/cpu/start-reset.c
index e0df676274..fcfdce6bff 100644
--- a/arch/arm/cpu/start-reset.c
+++ b/arch/arm/cpu/start-reset.c
@@ -29,6 +29,9 @@
/*
* The actual reset vector. This code is position independent and usually
* does not run at the address it's linked at.
+ *
+ * This is either executed in the pbl image (if enabled) or in the regular
+ * image.
*/
void __naked __bare_init reset(void)
{
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index 9775b7f17f..97098f3b36 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -27,7 +27,7 @@
#ifdef CONFIG_PBL_IMAGE
/*
- * First function in the pbl image. We get here from
+ * First function in the uncompressed image. We get here from
* the pbl.
*/
void __naked __section(.text_entry) start(void)
@@ -44,6 +44,9 @@ void __naked __section(.text_entry) start(void)
}
#else
+/*
+ * First function in the image without pbl support
+ */
void __naked __section(.text_entry) start(void)
{
barebox_arm_head();
@@ -53,22 +56,16 @@ void __naked __section(.text_entry) start(void)
* Board code can jump here by either returning from board_init_lowlevel
* or by calling this function directly.
*/
-void __naked __section(.text_ll_return) board_init_lowlevel_return(void)
+void __naked board_init_lowlevel_return(void)
{
- uint32_t r, addr, offset;
-
- /*
- * Get runtime address of this function. Do not
- * put any code above this.
- */
- __asm__ __volatile__("1: adr %0, 1b":"=r"(addr));
+ uint32_t r, offset;
/* Setup the stack */
r = STACK_BASE + STACK_SIZE - 16;
__asm__ __volatile__("mov sp, %0" : : "r"(r));
/* Get offset between linked address and runtime address */
- offset = (uint32_t)__ll_return - addr;
+ offset = get_runtime_offset();
/* relocate to link address if necessary */
if (offset)
diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h
index 0fe6c47bae..8862f367c2 100644
--- a/arch/arm/include/asm/barebox-arm.h
+++ b/arch/arm/include/asm/barebox-arm.h
@@ -33,10 +33,10 @@ int board_init(void);
int dram_init (void);
extern char __exceptions_start[], __exceptions_stop[];
-extern char __ll_return[];
void board_init_lowlevel(void);
void board_init_lowlevel_return(void);
void arch_init_lowlevel(void);
+uint32_t get_runtime_offset(void);
#endif /* _BAREBOX_ARM_H_ */
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 9d0ff7a856..2e624cdf84 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -16,6 +16,8 @@ obj-y += lib1funcs.o
obj-y += ashrdi3.o
obj-y += ashldi3.o
obj-y += lshrdi3.o
+obj-y += runtime-offset.o
+pbl-y += runtime-offset.o
obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memcpy.o
obj-$(CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS) += memset.o
obj-$(CONFIG_ARM_UNWIND) += unwind.o
diff --git a/arch/arm/lib/armlinux.c b/arch/arm/lib/armlinux.c
index 182930f0a7..9c134ed4b8 100644
--- a/arch/arm/lib/armlinux.c
+++ b/arch/arm/lib/armlinux.c
@@ -75,7 +75,7 @@ void armlinux_set_revision(unsigned int rev)
#ifdef CONFIG_ENVIRONMENT_VARIABLES
export_env_ull("armlinux_system_rev", rev);
#else
- return armlinux_system_rev;
+ armlinux_system_rev = rev;
#endif
}
diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S
index 465cb55d24..bac1a04f87 100644
--- a/arch/arm/lib/barebox.lds.S
+++ b/arch/arm/lib/barebox.lds.S
@@ -36,8 +36,6 @@ SECTIONS
_stext = .;
_text = .;
*(.text_entry*)
- __ll_return = .;
- *(.text_ll_return*)
__bare_init_start = .;
*(.text_bare_init*)
__bare_init_end = .;
diff --git a/arch/arm/lib/runtime-offset.S b/arch/arm/lib/runtime-offset.S
new file mode 100644
index 0000000000..ffa668cd7e
--- /dev/null
+++ b/arch/arm/lib/runtime-offset.S
@@ -0,0 +1,17 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+
+/*
+ * Get the offset between the link address and the address
+ * we are currently running at.
+ */
+ENTRY(get_runtime_offset)
+1: adr r0, 1b
+ ldr r1, linkadr
+ subs r0, r1, r0
+THUMB( subs r0, r0, #1)
+ mov pc, lr
+
+linkadr:
+.word get_runtime_offset
+ENDPROC(get_runtime_offset)
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index ce5edaa336..7ab812abc5 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -27,6 +27,7 @@ config ARCH_TEXT_BASE
default 0x4fc00000 if MACH_MX6Q_ARM2
default 0x97f00000 if MACH_CCMX51
default 0x4fc00000 if MACH_SABRELITE
+ default 0x7fe00000 if MACH_TX53
config BOARDINFO
default "Eukrea CPUIMX25" if MACH_EUKREA_CPUIMX25
@@ -53,6 +54,7 @@ config BOARDINFO
default "Freescale i.MX6q armadillo2" if MACH_MX6Q_ARM2
default "ConnectCore i.MX51" if MACH_CCMX51
default "Sabre Lite" if MACH_SABRELITE
+ default "Ka-Ro tx53" if MACH_TX53
choice
prompt "Select boot mode"
@@ -459,6 +461,12 @@ config MACH_TQMA53_1GB_RAM
help
use 1GiB of SDRAM (512MiB otherwise)
+config MACH_TX53
+ bool "Ka-Ro TX53"
+ select HAVE_DEFAULT_ENVIRONMENT_NEW
+ help
+ Say Y here if you are using the Ka-Ro tx53 board
+
endchoice
endif
diff --git a/arch/arm/mach-imx/clocksource.c b/arch/arm/mach-imx/clocksource.c
index fccc2f70ff..2c6f6a08e6 100644
--- a/arch/arm/mach-imx/clocksource.c
+++ b/arch/arm/mach-imx/clocksource.c
@@ -28,17 +28,45 @@
#include <common.h>
#include <init.h>
#include <clock.h>
+#include <errno.h>
#include <notifier.h>
#include <mach/imx-regs.h>
#include <mach/clock.h>
#include <io.h>
-#define GPT(x) __REG(IMX_TIM1_BASE + (x))
-#define timer_base IOMEM(IMX_TIM1_BASE)
+/* Part 1: Registers */
+# define GPT_TCTL 0x00
+# define GPT_TPRER 0x04
+
+/* Part 2: Bitfields */
+#define TCTL_SWR (1 << 15) /* Software reset */
+#define IMX1_TCTL_FRR (1 << 8) /* Freerun / restart */
+#define IMX31_TCTL_FRR (1 << 9) /* Freerun / restart */
+#define IMX1_TCTL_CLKSOURCE_IPG (1 << 1) /* Clock source bit position */
+#define IMX31_TCTL_CLKSOURCE_IPG (1 << 6) /* Clock source bit position */
+#define TCTL_TEN (1 << 0) /* Timer enable */
+
+struct imx_gpt_regs {
+ unsigned int tcn;
+ uint32_t tctl_val;
+};
+
+static struct imx_gpt_regs regs_imx1 = {
+ .tcn = 0x10,
+ .tctl_val = IMX1_TCTL_FRR | IMX1_TCTL_CLKSOURCE_IPG | TCTL_TEN,
+};
+
+static struct imx_gpt_regs regs_imx31 = {
+ .tcn = 0x24,
+ .tctl_val = IMX31_TCTL_FRR | IMX31_TCTL_CLKSOURCE_IPG | TCTL_TEN,
+};
+
+static struct imx_gpt_regs *regs;
+static void __iomem *timer_base;
static uint64_t imx_clocksource_read(void)
{
- return readl(timer_base + GPT_TCN);
+ return readl(timer_base + regs->tcn);
}
static struct clocksource cs = {
@@ -57,10 +85,20 @@ static struct notifier_block imx_clock_notifier = {
.notifier_call = imx_clocksource_clock_change,
};
-static int clocksource_init (void)
+static int imx_gpt_probe(struct device_d *dev)
{
int i;
- uint32_t val;
+ int ret;
+
+ /* one timer is enough */
+ if (timer_base)
+ return -EBUSY;
+
+ ret = dev_get_drvdata(dev, (unsigned long *)&regs);
+ if (ret)
+ return ret;
+
+ timer_base = dev_request_mem_region(dev, 0);
/* setup GP Timer 1 */
writel(TCTL_SWR, timer_base + GPT_TCTL);
@@ -81,9 +119,7 @@ static int clocksource_init (void)
writel(0, timer_base + GPT_TCTL); /* We have no udelay by now */
writel(0, timer_base + GPT_TPRER);
- val = readl(timer_base + GPT_TCTL);
- val |= TCTL_FRR | (1 << TCTL_CLKSOURCE) | TCTL_TEN; /* Freerun Mode, PERCLK1 input */
- writel(val, timer_base + GPT_TCTL);
+ writel(regs->tctl_val, timer_base + GPT_TCTL);
cs.mult = clocksource_hz2mult(imx_get_gptclk(), cs.shift);
@@ -94,7 +130,42 @@ static int clocksource_init (void)
return 0;
}
-core_initcall(clocksource_init);
+static __maybe_unused struct of_device_id imx_gpt_dt_ids[] = {
+ {
+ .compatible = "fsl,imx1-gpt",
+ .data = (unsigned long)&regs_imx1,
+ }, {
+ .compatible = "fsl,imx31-gpt",
+ .data = (unsigned long)&regs_imx31,
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct platform_device_id imx_gpt_ids[] = {
+ {
+ .name = "imx1-gpt",
+ .driver_data = (unsigned long)&regs_imx1,
+ }, {
+ .name = "imx31-gpt",
+ .driver_data = (unsigned long)&regs_imx31,
+ }, {
+ /* sentinel */
+ },
+};
+
+static struct driver_d imx_gpt_driver = {
+ .name = "imx-gpt",
+ .probe = imx_gpt_probe,
+ .of_compatible = DRV_OF_COMPAT(imx_gpt_dt_ids),
+ .id_table = imx_gpt_ids,
+};
+
+static int imx_gpt_init(void)
+{
+ return register_driver(&imx_gpt_driver);
+}
+coredevice_initcall(imx_gpt_init);
/*
* Watchdog Registers
diff --git a/arch/arm/mach-imx/gpio.c b/arch/arm/mach-imx/gpio.c
index 324794ae68..268e598195 100644
--- a/arch/arm/mach-imx/gpio.c
+++ b/arch/arm/mach-imx/gpio.c
@@ -27,28 +27,28 @@
#include <gpio.h>
#include <init.h>
-#if defined CONFIG_ARCH_IMX1 || defined CONFIG_ARCH_IMX21 || defined CONFIG_ARCH_IMX27
-#define GPIO_DR 0x1c
-#define GPIO_GDIR 0x00
-#define GPIO_PSR 0x24
-#define GPIO_ICR1 0x28
-#define GPIO_ICR2 0x2C
-#define GPIO_IMR 0x30
-#define GPIO_ISR 0x34
-#else
-#define GPIO_DR 0x00
-#define GPIO_GDIR 0x04
-#define GPIO_PSR 0x08
-#define GPIO_ICR1 0x0C
-#define GPIO_ICR2 0x10
-#define GPIO_IMR 0x14
-#define GPIO_ISR 0x18
-#define GPIO_ISR 0x18
-#endif
-
struct imx_gpio_chip {
void __iomem *base;
struct gpio_chip chip;
+ struct imx_gpio_regs *regs;
+};
+
+struct imx_gpio_regs {
+ unsigned int dr;
+ unsigned int gdir;
+ unsigned int psr;
+};
+
+static struct imx_gpio_regs regs_imx1 = {
+ .dr = 0x1c,
+ .gdir = 0x00,
+ .psr = 0x24,
+};
+
+static struct imx_gpio_regs regs_imx31 = {
+ .dr = 0x00,
+ .gdir = 0x04,
+ .psr = 0x08,
};
static void imx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
@@ -60,14 +60,14 @@ static void imx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
if (!base)
return;
- val = readl(base + GPIO_DR);
+ val = readl(base + imxgpio->regs->dr);
if (value)
val |= 1 << gpio;
else
val &= ~(1 << gpio);
- writel(val, base + GPIO_DR);
+ writel(val, base + imxgpio->regs->dr);
}
static int imx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
@@ -79,9 +79,9 @@ static int imx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
if (!base)
return -EINVAL;
- val = readl(base + GPIO_GDIR);
+ val = readl(base + imxgpio->regs->gdir);
val &= ~(1 << gpio);
- writel(val, base + GPIO_GDIR);
+ writel(val, base + imxgpio->regs->gdir);
return 0;
}
@@ -95,9 +95,9 @@ static int imx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int
gpio_set_value(gpio + chip->base, value);
- val = readl(base + GPIO_GDIR);
+ val = readl(base + imxgpio->regs->gdir);
val |= 1 << gpio;
- writel(val, base + GPIO_GDIR);
+ writel(val, base + imxgpio->regs->gdir);
return 0;
}
@@ -108,7 +108,7 @@ static int imx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
void __iomem *base = imxgpio->base;
u32 val;
- val = readl(base + GPIO_PSR);
+ val = readl(base + imxgpio->regs->psr);
return val & (1 << gpio) ? 1 : 0;
}
@@ -123,23 +123,80 @@ static struct gpio_ops imx_gpio_ops = {
static int imx_gpio_probe(struct device_d *dev)
{
struct imx_gpio_chip *imxgpio;
+ struct imx_gpio_regs *regs;
+ int ret;
+
+ ret = dev_get_drvdata(dev, (unsigned long *)&regs);
+ if (ret)
+ return ret;
imxgpio = xzalloc(sizeof(*imxgpio));
imxgpio->base = dev_request_mem_region(dev, 0);
imxgpio->chip.ops = &imx_gpio_ops;
- imxgpio->chip.base = -1;
+ if (dev->id < 0) {
+ imxgpio->chip.base = of_alias_get_id(dev->device_node, "gpio");
+ if (imxgpio->chip.base < 0)
+ return imxgpio->chip.base;
+ } else {
+ imxgpio->chip.base = dev->id * 32;
+ }
imxgpio->chip.ngpio = 32;
imxgpio->chip.dev = dev;
+ imxgpio->regs = regs;
gpiochip_add(&imxgpio->chip);
- dev_info(dev, "probed gpiochip%d with base %d\n", dev->id, imxgpio->chip.base);
+ dev_dbg(dev, "probed gpiochip%d with base %d\n", dev->id, imxgpio->chip.base);
return 0;
}
+static __maybe_unused struct of_device_id imx_gpio_dt_ids[] = {
+ {
+ .compatible = "fsl,imx1-gpio",
+ .data = (unsigned long)&regs_imx1,
+ }, {
+ .compatible = "fsl,imx21-gpio",
+ .data = (unsigned long)&regs_imx1,
+ }, {
+ .compatible = "fsl,imx27-gpio",
+ .data = (unsigned long)&regs_imx1,
+ }, {
+ .compatible = "fsl,imx31-gpio",
+ .data = (unsigned long)&regs_imx31,
+ }, {
+ .compatible = "fsl,imx35-gpio",
+ .data = (unsigned long)&regs_imx31,
+ }, {
+ .compatible = "fsl,imx51-gpio",
+ .data = (unsigned long)&regs_imx31,
+ }, {
+ .compatible = "fsl,imx53-gpio",
+ .data = (unsigned long)&regs_imx31,
+ }, {
+ .compatible = "fsl,imx6q-gpio",
+ .data = (unsigned long)&regs_imx31,
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct platform_device_id imx_gpio_ids[] = {
+ {
+ .name = "imx1-gpio",
+ .driver_data = (unsigned long)&regs_imx1,
+ }, {
+ .name = "imx31-gpio",
+ .driver_data = (unsigned long)&regs_imx31,
+ }, {
+ /* sentinel */
+ },
+};
+
static struct driver_d imx_gpio_driver = {
.name = "imx-gpio",
.probe = imx_gpio_probe,
+ .of_compatible = DRV_OF_COMPAT(imx_gpio_dt_ids),
+ .id_table = imx_gpio_ids,
};
static int imx_gpio_add(void)
diff --git a/arch/arm/mach-imx/imx1.c b/arch/arm/mach-imx/imx1.c
index 45d5a11485..b32e371275 100644
--- a/arch/arm/mach-imx/imx1.c
+++ b/arch/arm/mach-imx/imx1.c
@@ -16,10 +16,11 @@
static int imx1_init(void)
{
- add_generic_device("imx-gpio", 0, NULL, 0x0021c000, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, 0x0021c100, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, 0x0021c200, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 3, NULL, 0x0021c300, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpt", 0, NULL, 0x00202000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 0, NULL, 0x0021c000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 1, NULL, 0x0021c100, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 2, NULL, 0x0021c200, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 3, NULL, 0x0021c300, 0x100, IORESOURCE_MEM, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/imx21.c b/arch/arm/mach-imx/imx21.c
index 78e8d772ef..df3eaf2666 100644
--- a/arch/arm/mach-imx/imx21.c
+++ b/arch/arm/mach-imx/imx21.c
@@ -25,12 +25,13 @@ int imx_silicon_revision(void)
static int imx21_init(void)
{
- add_generic_device("imx-gpio", 0, NULL, 0x10015000, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, 0x10015100, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, 0x10015200, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 3, NULL, 0x10015300, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 4, NULL, 0x10015400, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 5, NULL, 0x10015500, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpt", 0, NULL, 0x10003000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 0, NULL, 0x10015000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 1, NULL, 0x10015100, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 2, NULL, 0x10015200, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 3, NULL, 0x10015300, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 4, NULL, 0x10015400, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 5, NULL, 0x10015500, 0x100, IORESOURCE_MEM, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/imx25.c b/arch/arm/mach-imx/imx25.c
index a9f58c4db6..dd10d58767 100644
--- a/arch/arm/mach-imx/imx25.c
+++ b/arch/arm/mach-imx/imx25.c
@@ -44,10 +44,12 @@ static int imx25_init(void)
add_generic_device("imx_iim", 0, NULL, IMX_IIM_BASE, SZ_4K,
IORESOURCE_MEM, &imx25_iim_pdata);
- add_generic_device("imx-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 3, NULL, 0x53f9c000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpt", 0, NULL, 0x53f90000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 3, NULL, 0x53f9c000, 0x1000, IORESOURCE_MEM, NULL);
+
return 0;
}
coredevice_initcall(imx25_init);
diff --git a/arch/arm/mach-imx/imx27.c b/arch/arm/mach-imx/imx27.c
index 2fc0af5f5f..32a32a33a6 100644
--- a/arch/arm/mach-imx/imx27.c
+++ b/arch/arm/mach-imx/imx27.c
@@ -69,12 +69,13 @@ static int imx27_init(void)
imx27_init_max();
- add_generic_device("imx-gpio", 0, NULL, 0x10015000, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, 0x10015100, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, 0x10015200, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 3, NULL, 0x10015300, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 4, NULL, 0x10015400, 0x100, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 5, NULL, 0x10015500, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpt", 0, NULL, 0x10003000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 0, NULL, 0x10015000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 1, NULL, 0x10015100, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 2, NULL, 0x10015200, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 3, NULL, 0x10015300, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 4, NULL, 0x10015400, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx1-gpio", 5, NULL, 0x10015500, 0x100, IORESOURCE_MEM, NULL);
return 0;
}
-coredevice_initcall(imx27_init);
+console_initcall(imx27_init);
diff --git a/arch/arm/mach-imx/imx31.c b/arch/arm/mach-imx/imx31.c
index 433ffb73b0..881c3e586e 100644
--- a/arch/arm/mach-imx/imx31.c
+++ b/arch/arm/mach-imx/imx31.c
@@ -21,9 +21,10 @@ static int imx31_init(void)
add_generic_device("imx_iim", 0, NULL, IMX_IIM_BASE, SZ_4K,
IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpt", 0, NULL, 0x53f90000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/imx35.c b/arch/arm/mach-imx/imx35.c
index ffe6979b36..579e14814d 100644
--- a/arch/arm/mach-imx/imx35.c
+++ b/arch/arm/mach-imx/imx35.c
@@ -52,9 +52,10 @@ static int imx35_init(void)
add_generic_device("imx_iim", 0, NULL, IMX_IIM_BASE, SZ_4K,
IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpt", 0, NULL, 0x53f90000, 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/imx51.c b/arch/arm/mach-imx/imx51.c
index a45bd599cb..022614ffde 100644
--- a/arch/arm/mach-imx/imx51.c
+++ b/arch/arm/mach-imx/imx51.c
@@ -74,10 +74,11 @@ static int imx51_init(void)
add_generic_device("imx_iim", 0, NULL, MX51_IIM_BASE_ADDR, SZ_4K,
IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 0, NULL, 0x73f84000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, 0x73f88000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, 0x73f8c000, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 3, NULL, 0x73f90000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpt", 0, NULL, 0x73fa0000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 0, NULL, 0x73f84000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 1, NULL, 0x73f88000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 2, NULL, 0x73f8c000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 3, NULL, 0x73f90000, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/imx53.c b/arch/arm/mach-imx/imx53.c
index 5bfc864ced..2d7c174e25 100644
--- a/arch/arm/mach-imx/imx53.c
+++ b/arch/arm/mach-imx/imx53.c
@@ -70,13 +70,15 @@ static int imx53_init(void)
add_generic_device("imx_iim", 0, NULL, MX53_IIM_BASE_ADDR, SZ_4K,
IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 0, NULL, MX53_GPIO1_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, MX53_GPIO2_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, MX53_GPIO3_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 3, NULL, MX53_GPIO4_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 4, NULL, MX53_GPIO5_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 5, NULL, MX53_GPIO6_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 6, NULL, MX53_GPIO7_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpt", 0, NULL, 0X53fa0000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 0, NULL, MX53_GPIO1_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 1, NULL, MX53_GPIO2_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 2, NULL, MX53_GPIO3_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 3, NULL, MX53_GPIO4_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 4, NULL, MX53_GPIO5_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 5, NULL, MX53_GPIO6_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 6, NULL, MX53_GPIO7_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
+
return 0;
}
coredevice_initcall(imx53_init);
diff --git a/arch/arm/mach-imx/imx6.c b/arch/arm/mach-imx/imx6.c
index 79b6502572..babf8fea80 100644
--- a/arch/arm/mach-imx/imx6.c
+++ b/arch/arm/mach-imx/imx6.c
@@ -54,13 +54,14 @@ void imx6_init_lowlevel(void)
static int imx6_init(void)
{
- add_generic_device("imx-gpio", 0, NULL, MX6_GPIO1_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 1, NULL, MX6_GPIO2_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 2, NULL, MX6_GPIO3_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 3, NULL, MX6_GPIO4_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 4, NULL, MX6_GPIO5_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 5, NULL, MX6_GPIO6_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
- add_generic_device("imx-gpio", 6, NULL, MX6_GPIO7_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpt", 0, NULL, 0x02098000, 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 0, NULL, MX6_GPIO1_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 1, NULL, MX6_GPIO2_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 2, NULL, MX6_GPIO3_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 3, NULL, MX6_GPIO4_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 4, NULL, MX6_GPIO5_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 5, NULL, MX6_GPIO6_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
+ add_generic_device("imx31-gpio", 6, NULL, MX6_GPIO7_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
return 0;
}
diff --git a/arch/arm/mach-imx/include/mach/imx1-regs.h b/arch/arm/mach-imx/include/mach/imx1-regs.h
index f940cdb4b2..d5ee3f58a6 100644
--- a/arch/arm/mach-imx/include/mach/imx1-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx1-regs.h
@@ -207,27 +207,4 @@
#define PD31_PF_TMR2OUT ( GPIO_PORTD | GPIO_PF | 31 )
#define PD31_BIN_SPI2_TXD ( GPIO_PORTD | GPIO_BIN | 31 )
-/*
- * Definitions for the clocksource driver
- */
-/* Part 1: Registers */
-# define GPT_TCTL 0x00
-# define GPT_TPRER 0x04
-# define GPT_TCMP 0x08
-# define GPT_TCR 0x0c
-# define GPT_TCN 0x10
-# define GPT_TSTAT 0x14
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<8) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (1) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#endif /* _IMX1_REGS_H */
diff --git a/arch/arm/mach-imx/include/mach/imx21-regs.h b/arch/arm/mach-imx/include/mach/imx21-regs.h
index a2c4d03643..98e73ef27e 100644
--- a/arch/arm/mach-imx/include/mach/imx21-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx21-regs.h
@@ -107,30 +107,6 @@
#define CCSR_32K_SR (1 << 15)
-/*
- * Definitions for the clocksource driver
- */
-/* Part 1: Registers */
-# define GPT_TCTL 0x00
-# define GPT_TPRER 0x04
-# define GPT_TCMP 0x08
-# define GPT_TCR 0x0c
-# define GPT_TCN 0x10
-# define GPT_TSTAT 0x14
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_CC (1<<10) /* counter clear */
-#define TCTL_FRR (1<<8) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_CAPEN (1<<5) /* compare interrupt enable */
-#define TCTL_COMPEN (1<<4) /* compare interrupt enable */
-#define TCTL_CLKSOURCE (1) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#define IMX_CS0_BASE 0xC8000000
#define IMX_CS1_BASE 0xCC000000
#define IMX_CS2_BASE 0xD0000000
diff --git a/arch/arm/mach-imx/include/mach/imx25-regs.h b/arch/arm/mach-imx/include/mach/imx25-regs.h
index 174cc9ac12..5176b5e813 100644
--- a/arch/arm/mach-imx/include/mach/imx25-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx25-regs.h
@@ -104,33 +104,6 @@
#define CSCR_A(x) (WEIM_BASE + 8 + (x) * 0x10)
/*
- * Definitions for the clocksource driver
- *
- * These defines are using the i.MX1/27 notation
- * to reuse the clocksource code for these CPUs
- * on the i.MX35
- */
-/* Part 1: Registers */
-#define GPT_TCTL 0x00
-#define GPT_TPRER 0x04
-#define GPT_TCMP 0x10
-#define GPT_TCR 0x1c
-#define GPT_TCN 0x24
-#define GPT_TSTAT 0x08
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<9) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (6) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
-/*
* Watchdog Registers
*/
#define WCR __REG16(IMX_WDT_BASE + 0x00) /* Watchdog Control Register */
diff --git a/arch/arm/mach-imx/include/mach/imx27-regs.h b/arch/arm/mach-imx/include/mach/imx27-regs.h
index 19dcad9e9b..8686a9dfc3 100644
--- a/arch/arm/mach-imx/include/mach/imx27-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx27-regs.h
@@ -221,29 +221,6 @@
#define ESDCFG_TWTR (1 << 20)
#define ESDCFG_TXP(x) (((x) & 0x3) << 21)
-/*
- * Definitions for the clocksource driver
- */
-/* Part 1: Registers */
-# define GPT_TCTL 0x00
-# define GPT_TPRER 0x04
-# define GPT_TCMP 0x08
-# define GPT_TCR 0x0c
-# define GPT_TCN 0x10
-# define GPT_TSTAT 0x14
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<8) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (1) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#define IMX_CS0_BASE 0xC0000000
#define IMX_CS1_BASE 0xC8000000
#define IMX_CS2_BASE 0xD0000000
diff --git a/arch/arm/mach-imx/include/mach/imx31-regs.h b/arch/arm/mach-imx/include/mach/imx31-regs.h
index 280b42cb94..e3473d4dea 100644
--- a/arch/arm/mach-imx/include/mach/imx31-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx31-regs.h
@@ -53,33 +53,6 @@
#define IMX_CS5_BASE 0xB6000000
#define IMX_CS5_RANGE (32 * 1024 * 1024)
-/*
- * Definitions for the clocksource driver
- *
- * These defines are using the i.MX1/27 notation
- * to reuse the clocksource code for these CPUs
- * on the i.MX31
- */
-/* Part 1: Registers */
-#define GPT_TCTL 0x00
-#define GPT_TPRER 0x04
-#define GPT_TCMP 0x10
-#define GPT_TCR 0x1c
-#define GPT_TCN 0x24
-#define GPT_TSTAT 0x08
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<9) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (6) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#if 0
#define IMX_IO_BASE 0x00200000
diff --git a/arch/arm/mach-imx/include/mach/imx35-regs.h b/arch/arm/mach-imx/include/mach/imx35-regs.h
index 6f3fd26440..5a4ab90082 100644
--- a/arch/arm/mach-imx/include/mach/imx35-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx35-regs.h
@@ -112,32 +112,4 @@
#define CSCR_L(x) (WEIM_BASE + 4 + (x) * 0x10)
#define CSCR_A(x) (WEIM_BASE + 8 + (x) * 0x10)
-/*
- * Definitions for the clocksource driver
- *
- * These defines are using the i.MX1/27 notation
- * to reuse the clocksource code for these CPUs
- * on the i.MX35
- */
-/* Part 1: Registers */
-#define GPT_TCTL 0x00
-#define GPT_TPRER 0x04
-#define GPT_TCMP 0x10
-#define GPT_TCR 0x1c
-#define GPT_TCN 0x24
-#define GPT_TSTAT 0x08
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<9) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (6) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#endif /* __ASM_ARCH_MX35_REGS_H */
-
diff --git a/arch/arm/mach-imx/include/mach/imx51-regs.h b/arch/arm/mach-imx/include/mach/imx51-regs.h
index b51aa67c6f..c451004ecc 100644
--- a/arch/arm/mach-imx/include/mach/imx51-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx51-regs.h
@@ -5,13 +5,6 @@
#define IMX_WDT_BASE 0x73f98000
#define IMX_IOMUXC_BASE 0x73fa8000
-#define GPT_TCTL 0x00
-#define GPT_TPRER 0x04
-#define GPT_TCMP 0x10
-#define GPT_TCR 0x1c
-#define GPT_TCN 0x24
-#define GPT_TSTAT 0x08
-
/* WEIM registers */
#define WEIM_CSxGCR1(n) (((n) * 0x18) + 0x00)
#define WEIM_CSxGCR2(n) (((n) * 0x18) + 0x04)
@@ -22,18 +15,6 @@
#define WEIM_WIAR 0x94
#define WEIM_EAR 0x98
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<9) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (6) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#define MX51_IROM_BASE_ADDR 0x0
/*
diff --git a/arch/arm/mach-imx/include/mach/imx53-regs.h b/arch/arm/mach-imx/include/mach/imx53-regs.h
index 8fefc5463e..e57d1abdd0 100644
--- a/arch/arm/mach-imx/include/mach/imx53-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx53-regs.h
@@ -5,25 +5,6 @@
#define IMX_WDT_BASE 0X53F98000
#define IMX_IOMUXC_BASE 0X53FA8000
-#define GPT_TCTL 0x00
-#define GPT_TPRER 0x04
-#define GPT_TCMP 0x10
-#define GPT_TCR 0x1c
-#define GPT_TCN 0x24
-#define GPT_TSTAT 0x08
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<9) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (6) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#define MX53_IROM_BASE_ADDR 0x0
/*
diff --git a/arch/arm/mach-imx/include/mach/imx6-regs.h b/arch/arm/mach-imx/include/mach/imx6-regs.h
index c7b7481d0f..eca4fa663a 100644
--- a/arch/arm/mach-imx/include/mach/imx6-regs.h
+++ b/arch/arm/mach-imx/include/mach/imx6-regs.h
@@ -5,25 +5,6 @@
#define IMX_WDT_BASE 0x020bc000
#define IMX_IOMUXC_BASE 0x020e0000
-#define GPT_TCTL 0x00
-#define GPT_TPRER 0x04
-#define GPT_TCMP 0x10
-#define GPT_TCR 0x1c
-#define GPT_TCN 0x24
-#define GPT_TSTAT 0x08
-
-/* Part 2: Bitfields */
-#define TCTL_SWR (1<<15) /* Software reset */
-#define TCTL_FRR (1<<9) /* Freerun / restart */
-#define TCTL_CAP (3<<6) /* Capture Edge */
-#define TCTL_OM (1<<5) /* output mode */
-#define TCTL_IRQEN (1<<4) /* interrupt enable */
-#define TCTL_CLKSOURCE (6) /* Clock source bit position */
-#define TCTL_TEN (1) /* Timer enable */
-#define TPRER_PRES (0xff) /* Prescale */
-#define TSTAT_CAPT (1<<1) /* Capture event */
-#define TSTAT_COMP (1) /* Compare event */
-
#define MX6_AIPS1_ARB_BASE_ADDR 0x02000000
#define MX6_AIPS2_ARB_BASE_ADDR 0x02100000
diff --git a/arch/arm/mach-imx/iomux-v3.c b/arch/arm/mach-imx/iomux-v3.c
index d952caad1e..948b610b10 100644
--- a/arch/arm/mach-imx/iomux-v3.c
+++ b/arch/arm/mach-imx/iomux-v3.c
@@ -33,6 +33,10 @@ int mxc_iomux_v3_setup_pad(iomux_v3_cfg_t pad)
u32 pad_ctrl_ofs = (pad & MUX_PAD_CTRL_OFS_MASK) >> MUX_PAD_CTRL_OFS_SHIFT;
u32 pad_ctrl = (pad & MUX_PAD_CTRL_MASK) >> MUX_PAD_CTRL_SHIFT;
+ debug("%s: mux 0x%08x -> 0x%04x pad: 0x%08x -> 0x%04x sel_inp: 0x%08x -> 0x%04x\n",
+ __func__, mux_mode, mux_ctrl_ofs, pad_ctrl, pad_ctrl_ofs, sel_input,
+ sel_input_ofs);
+
if (mux_ctrl_ofs)
__raw_writel(mux_mode, base + mux_ctrl_ofs);
diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig
index 6f324a0af8..ff295f144c 100644
--- a/arch/arm/mach-mxs/Kconfig
+++ b/arch/arm/mach-mxs/Kconfig
@@ -4,6 +4,7 @@ config ARCH_TEXT_BASE
hex
default 0x41000000 if MACH_MX23EVK
default 0x42000000 if MACH_CHUMBY
+ default 0x42000000 if MACH_IMX233_OLINUXINO
default 0x47000000 if MACH_TX28
default 0x47000000 if MACH_MX28EVK
default 0x47000000 if MACH_CFA10036
@@ -11,6 +12,7 @@ config ARCH_TEXT_BASE
config BOARDINFO
default "Freescale i.MX23-EVK" if MACH_MX23EVK
default "Chumby Falconwing" if MACH_CHUMBY
+ default "Olimex.ltd imx233-olinuxino" if MACH_IMX233_OLINUXINO
default "Karo TX28" if MACH_TX28
default "Freescale i.MX28-EVK" if MACH_MX28EVK
default "Crystalfontz CFA-10036" if MACH_CFA10036
@@ -47,6 +49,11 @@ config MACH_CHUMBY
Say Y here if you are using the "chumby one" aka falconwing from
Chumby Industries
+config MACH_IMX233_OLINUXINO
+ bool "Olimex.ltd imx223-olinuxino"
+ help
+ Say Y here if you are using the imx233-olinuxino
+
endchoice
endif
diff --git a/arch/arm/mach-mxs/imx.c b/arch/arm/mach-mxs/imx.c
index 599a510aea..ab32f10351 100644
--- a/arch/arm/mach-mxs/imx.c
+++ b/arch/arm/mach-mxs/imx.c
@@ -16,6 +16,30 @@
#include <common.h>
#include <command.h>
#include <complete.h>
+#include <init.h>
+#include <io.h>
+#include <mach/imx-regs.h>
+
+#define HW_RTC_PERSISTENT1 0x070
+
+static int imx_reset_usb_bootstrap(void)
+{
+ /*
+ * Clear USB boot mode.
+ *
+ * When the i.MX28 boots from USB, the ROM code sets this bit. When
+ * after a reset the ROM code detects that this bit is set it will
+ * boot from USB again. This means that if we boot once from USB the
+ * chip will continue to boot from USB until the next power cycle.
+ *
+ * To prevent this (and boot from the configured bootsource instead)
+ * clear this bit here.
+ */
+ writel(0x2, IMX_WDT_BASE + HW_RTC_PERSISTENT1 + BIT_CLR);
+
+ return 0;
+}
+device_initcall(imx_reset_usb_bootstrap);
extern void imx_dump_clocks(void);
diff --git a/arch/arm/mach-nomadik/8815.c b/arch/arm/mach-nomadik/8815.c
index d935026fbe..81c5ce16d8 100644
--- a/arch/arm/mach-nomadik/8815.c
+++ b/arch/arm/mach-nomadik/8815.c
@@ -21,6 +21,7 @@
#include <mach/hardware.h>
#include <asm/armlinux.h>
#include <generated/mach-types.h>
+#include <linux/amba/bus.h>
#include "clock.h"
@@ -28,12 +29,15 @@ static struct clk st8815_clk_48 = {
.rate = 48 * 1000 * 1000,
};
+static struct clk st8815_dummy;
+
void st8815_add_device_sdram(u32 size)
{
arm_add_mem_device("ram0", 0x00000000, size);
}
static struct clk_lookup clocks_lookups[] = {
+ CLKDEV_CON_ID("apb_pclk", &st8815_dummy),
CLKDEV_DEV_ID("uart-pl0110", &st8815_clk_48),
CLKDEV_DEV_ID("uart-pl0111", &st8815_clk_48),
};
@@ -49,7 +53,6 @@ postcore_initcall(st8815_clkdev_init);
void st8815_register_uart(unsigned id)
{
resource_size_t start;
- struct device_d *dev;
switch (id) {
case 0:
@@ -59,7 +62,5 @@ void st8815_register_uart(unsigned id)
start = NOMADIK_UART1_BASE;
break;
}
- dev = add_generic_device("uart-pl011", id, NULL, start, 4096,
- IORESOURCE_MEM, NULL);
- nmdk_clk_create(&st8815_clk_48, dev_name(dev));
+ amba_apb_device_add(NULL, "uart-pl011", id, start, 4096, NULL, 0);
}
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index 7abed0f8be..c0d02efc77 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -48,20 +48,7 @@ config ARCH_OMAP4
endchoice
-### Generic Clock configurations to be enabled by Mach - invisible to enable.
-config OMAP_CLOCK_UART
- bool
-config OMAP_CLOCK_UART2
- bool
-config OMAP_CLOCK_UART3
- bool
-config OMAP_CLOCK_I2C
- bool
-
# Blind enable all possible clocks.. think twice before you do this.
-config OMAP_CLOCK_ALL
- bool
-
config OMAP_CLOCK_SOURCE_S32K
bool
@@ -87,6 +74,13 @@ config OMAP_BUILD_IFT
prompt "build ift binary"
bool
+config OMAP_BUILD_SPI
+ prompt "build SPI binary"
+ bool
+ help
+ Say Y here if you want to build an barebox.spi image as used
+ on the AM35xx chips when booting form SPI NOR flash.
+
config ARCH_TEXT_BASE
hex
default 0x80e80000 if MACH_OMAP343xSDP
@@ -106,14 +100,12 @@ choice
config MACH_OMAP343xSDP
bool "Texas Instrument's SDP343x"
- select OMAP_CLOCK_ALL
depends on ARCH_OMAP3
help
Say Y here if you are using SDP343x platform
config MACH_BEAGLE
bool "Texas Instrument's Beagle Board"
- select OMAP_CLOCK_ALL
select HAVE_NOSHELL
depends on ARCH_OMAP3
help
@@ -121,7 +113,6 @@ config MACH_BEAGLE
config MACH_OMAP3EVM
bool "Texas Instrument's OMAP3 EVM"
- select OMAP_CLOCK_ALL
select HAVE_NOSHELL
depends on ARCH_OMAP3
help
@@ -146,7 +137,6 @@ config MACH_PCM049
config MACH_PCAAL1
bool "Phytec phyCARD-A-L1"
- select OMAP_CLOCK_ALL
select HAVE_NOSHELL
depends on ARCH_OMAP3
help
diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c
index bb5f30f355..ff49708b15 100644
--- a/arch/arm/mach-omap/gpio.c
+++ b/arch/arm/mach-omap/gpio.c
@@ -32,11 +32,10 @@
* published by the Free Software Foundation.
*/
#include <common.h>
-#include <mach/gpio.h>
#include <io.h>
#include <errno.h>
-
-#ifdef CONFIG_ARCH_OMAP3
+#include <gpio.h>
+#include <init.h>
#define OMAP_GPIO_OE 0x0034
#define OMAP_GPIO_DATAIN 0x0038
@@ -44,129 +43,115 @@
#define OMAP_GPIO_CLEARDATAOUT 0x0090
#define OMAP_GPIO_SETDATAOUT 0x0094
-static void __iomem *gpio_bank[] = {
- (void *)0x48310000,
- (void *)0x49050000,
- (void *)0x49052000,
- (void *)0x49054000,
- (void *)0x49056000,
- (void *)0x49058000,
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP4
-
-#define OMAP_GPIO_OE 0x0134
-#define OMAP_GPIO_DATAIN 0x0138
-#define OMAP_GPIO_DATAOUT 0x013c
-#define OMAP_GPIO_CLEARDATAOUT 0x0190
-#define OMAP_GPIO_SETDATAOUT 0x0194
-
-static void __iomem *gpio_bank[] = {
- (void *)0x4a310000,
- (void *)0x48055000,
- (void *)0x48057000,
- (void *)0x48059000,
- (void *)0x4805b000,
- (void *)0x4805d000,
+struct omap_gpio_chip {
+ void __iomem *base;
+ struct gpio_chip chip;
};
-#endif
-
-static inline void __iomem *get_gpio_base(int gpio)
-{
- return gpio_bank[gpio >> 5];
-}
-static inline int get_gpio_index(int gpio)
+static inline int omap_get_gpio_index(int gpio)
{
return gpio & 0x1f;
}
-static inline int gpio_valid(int gpio)
+static void omap_gpio_set_value(struct gpio_chip *chip,
+ unsigned gpio, int value)
{
- if (gpio < 0)
- return -1;
- if (gpio / 32 < ARRAY_SIZE(gpio_bank))
- return 0;
- return -1;
-}
-
-static int check_gpio(int gpio)
-{
- if (gpio_valid(gpio) < 0) {
- printf("ERROR : check_gpio: invalid GPIO %d\n", gpio);
- return -1;
- }
- return 0;
-}
-
-void gpio_set_value(unsigned gpio, int value)
-{
- void __iomem *reg;
+ struct omap_gpio_chip *omapgpio =
+ container_of(chip, struct omap_gpio_chip, chip);
+ void __iomem *base = omapgpio->base;
u32 l = 0;
- if (check_gpio(gpio) < 0)
- return;
-
- reg = get_gpio_base(gpio);
-
if (value)
- reg += OMAP_GPIO_SETDATAOUT;
+ base += OMAP_GPIO_SETDATAOUT;
else
- reg += OMAP_GPIO_CLEARDATAOUT;
- l = 1 << get_gpio_index(gpio);
+ base += OMAP_GPIO_CLEARDATAOUT;
+
+ l = 1 << omap_get_gpio_index(gpio);
- __raw_writel(l, reg);
+ writel(l, base);
}
-int gpio_direction_input(unsigned gpio)
+static int omap_gpio_direction_input(struct gpio_chip *chip,
+ unsigned gpio)
{
- void __iomem *reg;
+ struct omap_gpio_chip *omapgpio =
+ container_of(chip, struct omap_gpio_chip, chip);
+ void __iomem *base = omapgpio->base;
u32 val;
- if (check_gpio(gpio) < 0)
- return -EINVAL;
-
- reg = get_gpio_base(gpio);
-
- reg += OMAP_GPIO_OE;
+ base += OMAP_GPIO_OE;
- val = __raw_readl(reg);
- val |= 1 << get_gpio_index(gpio);
- __raw_writel(val, reg);
+ val = readl(base);
+ val |= 1 << omap_get_gpio_index(gpio);
+ writel(val, base);
return 0;
}
-int gpio_direction_output(unsigned gpio, int value)
+static int omap_gpio_direction_output(struct gpio_chip *chip,
+ unsigned gpio, int value)
{
- void __iomem *reg;
+ struct omap_gpio_chip *omapgpio =
+ container_of(chip, struct omap_gpio_chip, chip);
+ void __iomem *base = omapgpio->base;
u32 val;
- if (check_gpio(gpio) < 0)
- return -EINVAL;
- reg = get_gpio_base(gpio);
+ omap_gpio_set_value(chip, gpio, value);
- gpio_set_value(gpio, value);
+ base += OMAP_GPIO_OE;
- reg += OMAP_GPIO_OE;
-
- val = __raw_readl(reg);
- val &= ~(1 << get_gpio_index(gpio));
- __raw_writel(val, reg);
+ val = readl(base);
+ val &= ~(1 << omap_get_gpio_index(gpio));
+ writel(val, base);
return 0;
}
-int gpio_get_value(unsigned gpio)
+static int omap_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
+{
+ struct omap_gpio_chip *omapgpio =
+ container_of(chip, struct omap_gpio_chip, chip);
+ void __iomem *base = omapgpio->base;
+
+ base += OMAP_GPIO_DATAIN;
+
+ return (readl(base) & (1 << omap_get_gpio_index(gpio))) != 0;
+
+}
+
+static struct gpio_ops omap_gpio_ops = {
+ .direction_input = omap_gpio_direction_input,
+ .direction_output = omap_gpio_direction_output,
+ .get = omap_gpio_get_value,
+ .set = omap_gpio_set_value,
+};
+
+static int omap_gpio_probe(struct device_d *dev)
{
- void __iomem *reg;
+ struct omap_gpio_chip *omapgpio;
+
+ omapgpio = xzalloc(sizeof(*omapgpio));
+ omapgpio->base = dev_request_mem_region(dev, 0);
+ omapgpio->chip.ops = &omap_gpio_ops;
+ omapgpio->chip.base = -1;
+ omapgpio->chip.ngpio = 32;
+ omapgpio->chip.dev = dev;
+ gpiochip_add(&omapgpio->chip);
- if (check_gpio(gpio) < 0)
- return -EINVAL;
- reg = get_gpio_base(gpio);
+ dev_dbg(dev, "probed gpiochip%d with base %d\n",
+ dev->id, omapgpio->chip.base);
+
+ return 0;
+}
- reg += OMAP_GPIO_DATAIN;
+static struct driver_d omap_gpio_driver = {
+ .name = "omap-gpio",
+ .probe = omap_gpio_probe,
+};
- return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0;
+static int omap_gpio_add(void)
+{
+ register_driver(&omap_gpio_driver);
+ return 0;
}
+coredevice_initcall(omap_gpio_add);
diff --git a/arch/arm/mach-omap/include/mach/emac_defs.h b/arch/arm/mach-omap/include/mach/emac_defs.h
new file mode 100644
index 0000000000..568de6a12a
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/emac_defs.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Based on:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.h
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+
+ * Modifications:
+ * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot.
+ *
+ */
+
+#ifndef _AM3517_EMAC_H_
+#define _AM3517_EMAC_H_
+
+#define EMAC_BASE_ADDR 0x5C010000
+#define EMAC_WRAPPER_BASE_ADDR 0x5C000000
+#define EMAC_WRAPPER_RAM_ADDR 0x5C020000
+#define EMAC_MDIO_BASE_ADDR 0x5C030000
+#define EMAC_HW_RAM_ADDR 0x01E20000
+
+#define EMAC_MDIO_BUS_FREQ 166000000 /* 166 MHZ check */
+#define EMAC_MDIO_CLOCK_FREQ 1000000 /* 2.0 MHz */
+
+#endif /* _AM3517_EMAC_H_ */
diff --git a/arch/arm/mach-omap/include/mach/xload.h b/arch/arm/mach-omap/include/mach/xload.h
index 844b57f0e5..63b68df15c 100644
--- a/arch/arm/mach-omap/include/mach/xload.h
+++ b/arch/arm/mach-omap/include/mach/xload.h
@@ -1,13 +1,11 @@
#ifndef _MACH_XLOAD_H
#define _MACH_XLOAD_H
-void *omap_xload_boot_nand(int offset, int size);
-void *omap_xload_boot_mmc(void);
-
enum omap_boot_src {
OMAP_BOOTSRC_UNKNOWN,
OMAP_BOOTSRC_MMC1,
OMAP_BOOTSRC_NAND,
+ OMAP_BOOTSRC_SPI1,
};
enum omap_boot_src omap3_bootsrc(void);
diff --git a/arch/arm/mach-omap/omap3_clock.c b/arch/arm/mach-omap/omap3_clock.c
index d129f5a71c..cfac7bc17f 100644
--- a/arch/arm/mach-omap/omap3_clock.c
+++ b/arch/arm/mach-omap/omap3_clock.c
@@ -670,18 +670,6 @@ static void per_clocks_enable(void)
/* Enable the ICLK for 32K Sync Timer as its used in udelay */
sr32(CM_REG(ICLKEN_WKUP), 2, 1, 0x1);
-#ifdef CONFIG_OMAP_CLOCK_UART
- /* Enable UART1 clocks */
- sr32(CM_REG(FCLKEN1_CORE), 13, 1, 0x1);
- sr32(CM_REG(ICLKEN1_CORE), 13, 1, 0x1);
-#endif
-#ifdef CONFIG_OMAP_CLOCK_I2C
- /* Turn on all 3 I2C clocks */
- sr32(CM_REG(FCLKEN1_CORE), 15, 3, 0x7);
- sr32(CM_REG(ICLKEN1_CORE), 15, 3, 0x7); /* I2C1,2,3 = on */
-#endif
-
-#ifdef CONFIG_OMAP_CLOCK_ALL
#define FCK_IVA2_ON 0x00000001
#define FCK_CORE1_ON 0x03fffe29
#define ICK_CORE1_ON 0x3ffffffb
@@ -706,7 +694,7 @@ static void per_clocks_enable(void)
sr32(CM_REG(ICLKEN_CAM), 0, 32, ICK_CAM_ON);
sr32(CM_REG(FCLKEN_PER), 0, 32, FCK_PER_ON);
sr32(CM_REG(ICLKEN_PER), 0, 32, ICK_PER_ON);
-#endif
+
/* Settle down my friend */
sdelay(1000);
}
diff --git a/arch/arm/mach-omap/omap3_generic.c b/arch/arm/mach-omap/omap3_generic.c
index af26af4f5d..5028e9a9e6 100644
--- a/arch/arm/mach-omap/omap3_generic.c
+++ b/arch/arm/mach-omap/omap3_generic.c
@@ -511,3 +511,22 @@ const struct gpmc_config omap3_nand_cfg = {
.base = 0x28000000,
.size = GPMC_SIZE_16M,
};
+
+static int omap3_gpio_init(void)
+{
+ add_generic_device("omap-gpio", 0, NULL, 0x48310000,
+ 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 1, NULL, 0x49050000,
+ 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 2, NULL, 0x49052000,
+ 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 3, NULL, 0x49054000,
+ 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 4, NULL, 0x49056000,
+ 0x100, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 5, NULL, 0x49058000,
+ 0x100, IORESOURCE_MEM, NULL);
+
+ return 0;
+}
+coredevice_initcall(omap3_gpio_init);
diff --git a/arch/arm/mach-omap/omap4_generic.c b/arch/arm/mach-omap/omap4_generic.c
index 617d786984..a159dfcb7e 100644
--- a/arch/arm/mach-omap/omap4_generic.c
+++ b/arch/arm/mach-omap/omap4_generic.c
@@ -572,3 +572,22 @@ const struct gpmc_config omap4_nand_cfg = {
.base = 0x28000000,
.size = GPMC_SIZE_16M,
};
+
+static int omap4_gpio_init(void)
+{
+ add_generic_device("omap-gpio", 0, NULL, 0x4a310100,
+ 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 1, NULL, 0x48055100,
+ 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 2, NULL, 0x48057100,
+ 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 3, NULL, 0x48059100,
+ 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 4, NULL, 0x4805b100,
+ 0x1000, IORESOURCE_MEM, NULL);
+ add_generic_device("omap-gpio", 5, NULL, 0x4805d100,
+ 0x1000, IORESOURCE_MEM, NULL);
+
+ return 0;
+}
+coredevice_initcall(omap4_gpio_init);
diff --git a/arch/arm/mach-omap/xload.c b/arch/arm/mach-omap/xload.c
index 13024abac7..9fa8221ec9 100644
--- a/arch/arm/mach-omap/xload.c
+++ b/arch/arm/mach-omap/xload.c
@@ -7,16 +7,65 @@
#include <fcntl.h>
#include <mach/xload.h>
#include <sizes.h>
+#include <filetype.h>
-void *omap_xload_boot_nand(int offset, int size)
+static void *read_image_head(const char *name)
{
+ void *header = xmalloc(ARM_HEAD_SIZE);
+ struct cdev *cdev;
int ret;
- void *to = xmalloc(size);
+
+ cdev = cdev_open(name, O_RDONLY);
+ if (!cdev) {
+ printf("failed to open partition\n");
+ return NULL;
+ }
+
+ ret = cdev_read(cdev, header, ARM_HEAD_SIZE, 0, 0);
+ cdev_close(cdev);
+
+ if (ret != ARM_HEAD_SIZE) {
+ printf("failed to read from partition\n");
+ return NULL;
+ }
+
+ return header;
+}
+
+static unsigned int get_image_size(void *head)
+{
+ unsigned int ret = 0;
+ unsigned int *psize = head + ARM_HEAD_SIZE_OFFSET;
+
+ if (is_barebox_arm_head(head))
+ ret = *psize;
+ debug("Detected barebox image size %u\n", ret);
+
+ return ret;
+}
+
+static void *omap_xload_boot_nand(int offset)
+{
+ int ret;
+ int size;
+ void *to, *header;
struct cdev *cdev;
- devfs_add_partition("nand0", offset, size, DEVFS_PARTITION_FIXED, "x");
+ devfs_add_partition("nand0", offset, SZ_1M, DEVFS_PARTITION_FIXED, "x");
dev_add_bb_dev("x", "bbx");
+ header = read_image_head("bbx");
+ if (header == NULL)
+ return NULL;
+
+ size = get_image_size(header);
+ if (!size) {
+ printf("failed to get image size\n");
+ return NULL;
+ }
+
+ to = xmalloc(size);
+
cdev = cdev_open("bbx", O_RDONLY);
if (!cdev) {
printf("failed to open nand\n");
@@ -32,7 +81,7 @@ void *omap_xload_boot_nand(int offset, int size)
return to;
}
-void *omap_xload_boot_mmc(void)
+static void *omap_xload_boot_mmc(void)
{
int ret;
void *buf;
@@ -54,6 +103,42 @@ void *omap_xload_boot_mmc(void)
return buf;
}
+static void *omap_xload_boot_spi(int offset)
+{
+ int ret;
+ int size;
+ void *to, *header;
+ struct cdev *cdev;
+
+ devfs_add_partition("m25p0", offset, SZ_1M, DEVFS_PARTITION_FIXED, "x");
+
+ header = read_image_head("x");
+ if (header == NULL)
+ return NULL;
+
+ size = get_image_size(header);
+ if (!size) {
+ printf("failed to get image size\n");
+ return NULL;
+ }
+
+ to = xmalloc(size);
+
+ cdev = cdev_open("x", O_RDONLY);
+ if (!cdev) {
+ printf("failed to open spi flash\n");
+ return NULL;
+ }
+
+ ret = cdev_read(cdev, to, size, 0, 0);
+ if (ret != size) {
+ printf("failed to read from spi flash\n");
+ return NULL;
+ }
+
+ return to;
+}
+
enum omap_boot_src omap_bootsrc(void)
{
#if defined(CONFIG_ARCH_OMAP3)
@@ -80,7 +165,11 @@ int run_shell(void)
printf("unknown boot source. Fall back to nand\n");
case OMAP_BOOTSRC_NAND:
printf("booting from NAND\n");
- func = omap_xload_boot_nand(SZ_128K, SZ_256K);
+ func = omap_xload_boot_nand(SZ_128K);
+ break;
+ case OMAP_BOOTSRC_SPI1:
+ printf("booting from SPI1\n");
+ func = omap_xload_boot_spi(SZ_128K);
break;
}
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 02a5f97272..5c75e11e98 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -30,6 +30,7 @@
#include <linux/clkdev.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/amba/bus.h>
#include <io.h>
#include <asm/hardware/arm_timer.h>
@@ -47,6 +48,8 @@ struct clk {
unsigned long rate;
};
+static struct clk ref_clk_dummy;
+
static struct clk ref_clk_24 = {
.rate = 24000000,
};
@@ -141,6 +144,7 @@ static int vpb_clocksource_init(void)
core_initcall(vpb_clocksource_init);
static struct clk_lookup clocks_lookups[] = {
+ CLKDEV_CON_ID("apb_pclk", &ref_clk_dummy),
CLKDEV_DEV_ID("uart-pl0110", &ref_clk_24),
CLKDEV_DEV_ID("uart-pl0111", &ref_clk_24),
CLKDEV_DEV_ID("uart-pl0112", &ref_clk_24),
@@ -175,8 +179,7 @@ void versatile_register_uart(unsigned id)
default:
return;
}
- add_generic_device("uart-pl011", id, NULL, start, 4096,
- IORESOURCE_MEM, NULL);
+ amba_apb_device_add(NULL, "uart-pl011", id, start, 4096, NULL, 0);
}
void __noreturn reset_cpu (unsigned long ignored)
diff --git a/arch/arm/pbl/zbarebox.lds.S b/arch/arm/pbl/zbarebox.lds.S
index 2dca278318..37af4e913e 100644
--- a/arch/arm/pbl/zbarebox.lds.S
+++ b/arch/arm/pbl/zbarebox.lds.S
@@ -39,8 +39,6 @@ SECTIONS
_stext = .;
_text = .;
*(.text_head_entry*)
- __ll_return = .;
- *(.text_ll_return*)
__bare_init_start = .;
*(.text_bare_init*)
__bare_init_end = .;
diff --git a/arch/nios2/include/asm/dma-mapping.h b/arch/nios2/include/asm/dma-mapping.h
index 9819a973e7..620c207a03 100644
--- a/arch/nios2/include/asm/dma-mapping.h
+++ b/arch/nios2/include/asm/dma-mapping.h
@@ -6,7 +6,6 @@
#include <asm/cache.h>
-
/* dma_alloc_coherent() return cache-line aligned allocation which is mapped
* to uncached io region.
*
@@ -14,6 +13,7 @@
* 0x80000000 for nommu, 0xe0000000 for mmu
*/
+#if (DCACHE_SIZE != 0)
static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
{
void *addr = malloc(len + DCACHE_LINE_SIZE);
@@ -25,11 +25,23 @@ static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
~(DCACHE_LINE_SIZE - 1) & ~(IO_REGION_BASE);
return (void *)(*handle | IO_REGION_BASE);
}
+#else
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
+{
+ void *addr = malloc(len);
+ if (!addr)
+ return 0;
+ *handle = (unsigned long)addr;
+ return (void *)(*handle | IO_REGION_BASE);
+}
+#endif
+#if (DCACHE_SIZE != 0)
#define dma_alloc dma_alloc
static inline void *dma_alloc(size_t size)
{
return xmemalign(DCACHE_LINE_SIZE, ALIGN(size, DCACHE_LINE_SIZE));
}
+#endif
#endif /* __ASM_NIOS2_DMA_MAPPING_H */
diff --git a/arch/openrisc/Makefile b/arch/openrisc/Makefile
index 1f4b1755d4..fd8bbbf4d7 100644
--- a/arch/openrisc/Makefile
+++ b/arch/openrisc/Makefile
@@ -1,7 +1,5 @@
CPPFLAGS += -D__OR1K__ -ffixed-r10 -mhard-mul -mhard-div
-LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-
board-$(CONFIG_GENERIC) := generic
KALLSYMS += --symbol-prefix=_
@@ -20,6 +18,4 @@ common-y += $(BOARD)
common-y += arch/openrisc/lib/
common-y += arch/openrisc/cpu/
-common-y += $(LIBGCC)
-
lds-y += arch/openrisc/cpu/barebox.lds
diff --git a/arch/openrisc/lib/Makefile b/arch/openrisc/lib/Makefile
index aaf93cbd20..0b3cc5068c 100644
--- a/arch/openrisc/lib/Makefile
+++ b/arch/openrisc/lib/Makefile
@@ -4,3 +4,4 @@ obj-y += cpuinfo.o
obj-y += muldi3.o
obj-y += lshrdi3.o
obj-y += ashldi3.o
+obj-y += ashrdi3.o
diff --git a/arch/openrisc/lib/ashrdi3.S b/arch/openrisc/lib/ashrdi3.S
new file mode 100644
index 0000000000..c656d9fb6e
--- /dev/null
+++ b/arch/openrisc/lib/ashrdi3.S
@@ -0,0 +1,59 @@
+/*
+ * (C) Copyright 2012 - Franck JULLIEN <elec4fun@gmail.com>
+ *
+ * Extracted from gcc generated assembly.
+ *
+ * Extended precision shifts.
+ *
+ * R3/R4 (MSW, LSW) has 64 bit value
+ * R5 has shift count
+ * result in R11/R12
+ *
+ * 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
+ */
+
+
+.globl __ashrdi3
+
+__ashrdi3:
+ l.sfeqi r5,0x0 /* if count = 0, go out */
+ l.bf out
+
+ l.addi r6,r0,0x20 /* r6 = 32 */
+ l.sub r6,r6,r5 /* r6 = 32 - count */
+ l.sfgtsi r6,0x0 /* if count >= 32 */
+ l.bnf more_than_32 /* branch to more_than_32 */
+ l.nop 0x0
+
+
+ less_than_32:
+ l.sll r6,r3,r6 /* r6 gets the bits moved from MSW to LSW */
+ l.srl r4,r4,r5 /* shift LSW */
+ l.sra r5,r3,r5 /* shift MSW to r5 */
+ l.or r4,r6,r4 /* LSW gets bits shifted from MSW */
+ l.ori r3,r5,0x0 /* r3 = MSW */
+
+ out:
+ l.ori r11,r3,0x0
+ l.jr r9
+ l.ori r12,r4,0x0
+
+ more_than_32:
+ l.srai r5,r3,0x1f /* r5 = MSW sign extended */
+ l.sub r4,r0,r6 /* r4 = -r6, the number of bits above 32 */
+ l.sra r4,r3,r4 /* LSW gets bits shifted from MSB */
+ l.j out /* go out */
+ l.ori r3,r5,0x0 /* r3 = MSW */
diff --git a/arch/ppc/boards/pcm030/pcm030.c b/arch/ppc/boards/pcm030/pcm030.c
index 01becdef99..ae7f7f8c96 100644
--- a/arch/ppc/boards/pcm030/pcm030.c
+++ b/arch/ppc/boards/pcm030/pcm030.c
@@ -26,8 +26,7 @@
#include <common.h>
#include <driver.h>
#include <init.h>
-#include <mach/mpc5xxx.h>
-#include <mach/fec.h>
+#include <fec.h>
#include <types.h>
#include <partition.h>
#include <memory.h>
@@ -35,7 +34,7 @@
#include <linux/stat.h>
#include <fs.h>
-static struct mpc5xxx_fec_platform_data fec_info = {
+static struct fec_platform_data fec_info = {
.xcv_type = MII100,
};
diff --git a/arch/ppc/mach-mpc5xxx/include/mach/fec.h b/arch/ppc/mach-mpc5xxx/include/mach/fec.h
deleted file mode 100644
index a3e04b4e9d..0000000000
--- a/arch/ppc/mach-mpc5xxx/include/mach/fec.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __INCLUDE_ASM_ARCH_FEC_H
-#define __INCLUDE_ASM_ARCH_FEC_H
-
-struct mpc5xxx_fec_platform_data {
- ulong xcv_type;
-};
-
-typedef enum {
- SEVENWIRE, /* 7-wire */
- MII10, /* MII 10Mbps */
- MII100 /* MII 100Mbps */
-} xceiver_type;
-
-#endif /* __INCLUDE_ASM_ARCH_FEC_H */
diff --git a/arch/sandbox/board/Makefile b/arch/sandbox/board/Makefile
index 266c3a3cec..5104f5cb26 100644
--- a/arch/sandbox/board/Makefile
+++ b/arch/sandbox/board/Makefile
@@ -2,5 +2,6 @@ obj-y += board.o
obj-y += clock.o
obj-y += hostfile.o
obj-y += console.o
+obj-y += devices.o
extra-y += barebox.lds
diff --git a/arch/sandbox/board/console.c b/arch/sandbox/board/console.c
index 18b63e1d2d..b0afa54d95 100644
--- a/arch/sandbox/board/console.c
+++ b/arch/sandbox/board/console.c
@@ -44,6 +44,6 @@ int barebox_register_console(char *name, int stdinfd, int stdoutfd)
data->stdoutfd = stdoutfd;
data->stdinfd = stdinfd;
- return register_device(dev);
+ return sandbox_add_device(dev);
}
diff --git a/arch/sandbox/board/devices.c b/arch/sandbox/board/devices.c
new file mode 100644
index 0000000000..dba0d5d893
--- /dev/null
+++ b/arch/sandbox/board/devices.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2 only
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+
+static LIST_HEAD(sandbox_device_list);
+
+int sandbox_add_device(struct device_d *dev)
+{
+ list_add(&dev->list, &sandbox_device_list);
+
+ return 0;
+}
+
+static int sandbox_device_init(void)
+{
+ struct device_d *dev, *tmp;
+
+ list_for_each_entry_safe(dev, tmp, &sandbox_device_list, list) {
+ /* reset the list_head before registering for real */
+ dev->list.prev = NULL;
+ dev->list.next = NULL;
+ register_device(dev);
+ }
+
+ return 0;
+}
+postcore_initcall(sandbox_device_init);
diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c
index f5acc785ec..2cc7c1fbde 100644
--- a/arch/sandbox/board/hostfile.c
+++ b/arch/sandbox/board/hostfile.c
@@ -99,7 +99,22 @@ device_initcall(hf_init);
int barebox_register_filedev(struct hf_platform_data *hf)
{
- return !add_generic_device("hostfile", DEVICE_ID_DYNAMIC, NULL, hf->base, hf->size,
- IORESOURCE_MEM, hf);
+ struct device_d *dev;
+ struct resource *res;
+
+ dev = xzalloc(sizeof(*dev));
+ strcpy(dev->name, "hostfile");
+ dev->id = DEVICE_ID_DYNAMIC;
+ dev->platform_data = hf;
+
+ res = xzalloc(sizeof(struct resource));
+ res[0].start = hf->base;
+ res[0].end = hf->base + hf->size - 1;
+ res[0].flags = IORESOURCE_MEM;
+
+ dev->resource = res;
+ dev->num_resources = 1;
+
+ return sandbox_add_device(dev);
}
diff --git a/arch/sandbox/mach-sandbox/include/mach/linux.h b/arch/sandbox/mach-sandbox/include/mach/linux.h
index 5917fe93de..259f2d8ee3 100644
--- a/arch/sandbox/mach-sandbox/include/mach/linux.h
+++ b/arch/sandbox/mach-sandbox/include/mach/linux.h
@@ -1,6 +1,9 @@
#ifndef __ASM_ARCH_LINUX_H
#define __ASM_ARCH_LINUX_H
+struct device_d;
+
+int sandbox_add_device(struct device_d *dev);
int linux_register_device(const char *name, void *start, void *end);
int tap_alloc(char *dev);
uint64_t linux_get_time(void);
diff --git a/arch/sandbox/os/common.c b/arch/sandbox/os/common.c
index 35bcf9d8bb..0a4b96a63e 100644
--- a/arch/sandbox/os/common.c
+++ b/arch/sandbox/os/common.c
@@ -352,10 +352,6 @@ int main(int argc, char *argv[])
break;
switch (opt) {
- case 'h':
- break;
- case 'm':
- break;
case 'i':
sprintf(str, "fd%d", fdno);
ret = add_image(optarg, str);
@@ -363,14 +359,8 @@ int main(int argc, char *argv[])
exit(1);
fdno++;
break;
- case 'e':
- break;
- case 'O':
- break;
- case 'I':
- break;
default:
- exit(1);
+ break;
}
}
diff --git a/commands/Kconfig b/commands/Kconfig
index f2756cc400..8767807408 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -468,7 +468,17 @@ config CMD_OFTREE
tristate
select OFTREE
prompt "oftree"
- select FDT
+ help
+ The oftree command has support for dumping devicetrees and, if
+ enabled, to probe devices from the devicetree
+
+config CMD_OFTREE_PROBE
+ bool
+ depends on CMD_OFTREE
+ select OFDEVICE
+ prompt "oftree probe support"
+ help
+ This enables the -p option to probe devices from the devicetree
endmenu
@@ -535,10 +545,11 @@ config CMD_LSMOD
depends on MODULES
prompt "lsmod"
-config CMD_BMP
+config CMD_SPLASH
bool
depends on VIDEO
- prompt "bmp"
+ select IMAGE_RENDERER
+ prompt "splash"
help
show bmp files on framebuffer devices
diff --git a/commands/Makefile b/commands/Makefile
index ccebd7f559..24bf46a80e 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -49,7 +49,7 @@ obj-$(CONFIG_CMD_VERSION) += version.o
obj-$(CONFIG_CMD_HELP) += help.o
obj-$(CONFIG_CMD_LSMOD) += lsmod.o
obj-$(CONFIG_CMD_INSMOD) += insmod.o
-obj-$(CONFIG_CMD_BMP) += bmp.o
+obj-$(CONFIG_CMD_SPLASH) += splash.o
obj-$(CONFIG_USB_GADGET_DFU) += dfu.o
obj-$(CONFIG_USB_GADGET_SERIAL) += usbserial.o
obj-$(CONFIG_CMD_GPIO) += gpio.o
diff --git a/commands/bmp.c b/commands/bmp.c
deleted file mode 100644
index 4130474931..0000000000
--- a/commands/bmp.c
+++ /dev/null
@@ -1,221 +0,0 @@
-#include <common.h>
-#include <command.h>
-#include <fs.h>
-#include <linux/stat.h>
-#include <errno.h>
-#include <malloc.h>
-#include <getopt.h>
-#include <fcntl.h>
-#include <fb.h>
-#include <bmp_layout.h>
-#include <asm/byteorder.h>
-
-static inline void set_pixel(struct fb_info *info, void *adr, int r, int g, int b)
-{
- u32 px;
-
- px = (r >> (8 - info->red.length)) << info->red.offset |
- (g >> (8 - info->green.length)) << info->green.offset |
- (b >> (8 - info->blue.length)) << info->blue.offset;
-
- switch (info->bits_per_pixel) {
- case 8:
- break;
- case 16:
- *(u16 *)adr = px;
- break;
- case 32:
- *(u32 *)adr = px;
- break;
- }
-}
-
-static int do_bmp(int argc, char *argv[])
-{
- int ret, opt, fd;
- char *fbdev = "/dev/fb0";
- void *fb, *offscreenbuf = NULL;
- struct fb_info info;
- struct bmp_image *bmp;
- char *bmpfile;
- int bmpsize;
- char *image;
- int sw, sh, width, height, startx = -1, starty = -1;
- int bits_per_pixel, fbsize;
- int xres, yres;
- int offscreen = 0;
- void *adr, *buf;
-
- while((opt = getopt(argc, argv, "f:x:y:o")) > 0) {
- switch(opt) {
- case 'f':
- fbdev = optarg;
- break;
- case 'x':
- startx = simple_strtoul(optarg, NULL, 0);
- break;
- case 'y':
- starty = simple_strtoul(optarg, NULL, 0);
- case 'o':
- offscreen = 1;
- }
- }
-
- if (optind == argc) {
- printf("no filename given\n");
- return 1;
- }
- bmpfile = argv[optind];
-
- fd = open(fbdev, O_RDWR);
- if (fd < 0) {
- perror("open");
- return 1;
- }
-
- fb = memmap(fd, PROT_READ | PROT_WRITE);
- if (fb == (void *)-1) {
- perror("memmap");
- goto failed_memmap;
- }
-
- ret = ioctl(fd, FBIOGET_SCREENINFO, &info);
- if (ret) {
- perror("ioctl");
- goto failed_memmap;
- }
-
- xres = info.xres;
- yres = info.yres;
-
- bmp = read_file(bmpfile, &bmpsize);
- if (!bmp) {
- printf("unable to read %s\n", bmpfile);
- goto failed_memmap;
- }
-
- if (bmp->header.signature[0] != 'B' ||
- bmp->header.signature[1] != 'M') {
- printf("No valid bmp file\n");
- }
-
- sw = le32_to_cpu(bmp->header.width);
- sh = le32_to_cpu(bmp->header.height);
-
- if (startx < 0) {
- startx = (xres - sw) / 2;
- if (startx < 0)
- startx = 0;
- }
-
- if (starty < 0) {
- starty = (yres - sh) / 2;
- if (starty < 0)
- starty = 0;
- }
-
- width = min(sw, xres - startx);
- height = min(sh, yres - starty);
-
- bits_per_pixel = le16_to_cpu(bmp->header.bit_count);
- fbsize = xres * yres * (info.bits_per_pixel >> 3);
-
- if (offscreen) {
- /* Don't fail if malloc fails, just continue rendering directly
- * on the framebuffer
- */
- offscreenbuf = malloc(fbsize);
- if (offscreenbuf)
- memcpy(offscreenbuf, fb, fbsize);
- }
-
- buf = offscreenbuf ? offscreenbuf : fb;
-
- if (bits_per_pixel == 8) {
- int x, y;
- struct bmp_color_table_entry *color_table = bmp->color_table;
-
- for (y = 0; y < height; y++) {
- image = (char *)bmp +
- le32_to_cpu(bmp->header.data_offset);
- image += (sh - y - 1) * sw * (bits_per_pixel >> 3);
- adr = buf + ((y + starty) * xres + startx) *
- (info.bits_per_pixel >> 3);
- for (x = 0; x < width; x++) {
- int pixel;
-
- pixel = *image;
-
- set_pixel(&info, adr, color_table[pixel].red,
- color_table[pixel].green,
- color_table[pixel].blue);
- adr += info.bits_per_pixel >> 3;
-
- image += bits_per_pixel >> 3;
- }
- }
- } else if (bits_per_pixel == 24) {
- int x, y;
-
- for (y = 0; y < height; y++) {
- image = (char *)bmp +
- le32_to_cpu(bmp->header.data_offset);
- image += (sh - y - 1) * sw * (bits_per_pixel >> 3);
- adr = buf + ((y + starty) * xres + startx) *
- (info.bits_per_pixel >> 3);
- for (x = 0; x < width; x++) {
- char *pixel;
-
- pixel = image;
-
- set_pixel(&info, adr, pixel[2], pixel[1],
- pixel[0]);
- adr += info.bits_per_pixel >> 3;
-
- image += bits_per_pixel >> 3;
- }
- }
- } else
- printf("bmp: illegal bits per pixel value: %d\n", bits_per_pixel);
-
- if (offscreenbuf) {
- memcpy(fb, offscreenbuf, fbsize);
- free(offscreenbuf);
- }
-
- free(bmp);
- close(fd);
-
- return 0;
-
-failed_memmap:
- close(fd);
-
- return 1;
-}
-
-BAREBOX_CMD_HELP_START(bmp)
-BAREBOX_CMD_HELP_USAGE("bmp [OPTIONS] FILE\n")
-BAREBOX_CMD_HELP_SHORT("Show the bitmap FILE on the framebuffer.\n")
-BAREBOX_CMD_HELP_OPT ("-f <fb>", "framebuffer device (/dev/fb0)\n")
-BAREBOX_CMD_HELP_OPT ("-x <xofs>", "x offset (default center)\n")
-BAREBOX_CMD_HELP_OPT ("-y <yofs>", "y offset (default center)\n")
-BAREBOX_CMD_HELP_OPT ("-o", "render offscreen\n")
-BAREBOX_CMD_HELP_END
-
-/**
- * @page bmp_command
-
-This command displays a graphics in the bitmap (.bmp) format on the
-framebuffer. Currently the bmp command supports images with 8 and 24 bit
-color depth.
-
-\todo What does the -o (offscreen) option do?
-
- */
-
-BAREBOX_CMD_START(bmp)
- .cmd = do_bmp,
- .usage = "show a bmp image",
- BAREBOX_CMD_HELP(cmd_bmp_help)
-BAREBOX_CMD_END
diff --git a/commands/echo.c b/commands/echo.c
index 0c0ed8086d..8929234aab 100644
--- a/commands/echo.c
+++ b/commands/echo.c
@@ -30,10 +30,9 @@ static int do_echo(int argc, char *argv[])
int fd = stdout, opt, newline = 1;
char *file = NULL;
int oflags = O_WRONLY | O_CREAT;
-#ifdef CONFIG_CMD_ECHO_E
char str[CONFIG_CBSIZE];
int process_escape = 0;
-#endif
+
/* We can't use getopt() here because we want to
* echo all things we don't understand.
*/
@@ -63,11 +62,9 @@ static int do_echo(int argc, char *argv[])
goto no_optarg_out;
optind++;
break;
-#ifdef CONFIG_CMD_ECHO_E
case 'e':
- process_escape = 1;
+ process_escape = IS_ENABLED(CONFIG_CMD_ECHO_E);
break;
-#endif
default:
goto exit_parse;
}
@@ -86,13 +83,12 @@ exit_parse:
for (i = optind; i < argc; i++) {
if (i > optind)
fputc(fd, ' ');
-#ifdef CONFIG_CMD_ECHO_E
if (process_escape) {
process_escape_sequence(argv[i], str, CONFIG_CBSIZE);
fputs(fd, str);
- } else
-#endif
+ } else {
fputs(fd, argv[i]);
+ }
}
if (newline)
diff --git a/commands/global.c b/commands/global.c
index 7e147a9ac4..427a231a9e 100644
--- a/commands/global.c
+++ b/commands/global.c
@@ -21,39 +21,68 @@
#include <command.h>
#include <globalvar.h>
#include <environment.h>
+#include <getopt.h>
-static int do_global(int argc, char *argv[])
+static int globalvar_set(char* name, char* value)
{
int ret;
+
+ ret = globalvar_add_simple(name);
+
+ if (value) {
+ char *tmp = asprintf("global.%s", name);
+ ret = setenv(tmp, value);
+ free(tmp);
+ }
+
+ return ret ? 1 : 0;
+}
+
+static int do_global(int argc, char *argv[])
+{
+ int opt;
+ int do_set_match = 0;
char *value;
- if (argc != 2)
+ while ((opt = getopt(argc, argv, "r")) > 0) {
+ switch (opt) {
+ case 'r':
+ do_set_match = 1;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
return COMMAND_ERROR_USAGE;
- value = strchr(argv[1], '=');
+ value = strchr(argv[0], '=');
if (value) {
*value = 0;
value++;
}
- ret = globalvar_add_simple(argv[1]);
+ if (do_set_match) {
+ if (!value)
+ value = "";
- if (value) {
- char *name = asprintf("global.%s", argv[1]);
- ret = setenv(name, value);
- free(name);
+ globalvar_set_match(argv[0], value);
+ return 0;
}
- return ret ? 1 : 0;
+ return globalvar_set(argv[0], value);
}
BAREBOX_CMD_HELP_START(global)
-BAREBOX_CMD_HELP_USAGE("global <var>[=<value]\n")
+BAREBOX_CMD_HELP_USAGE("global [-r] <var>[=<value]\n")
BAREBOX_CMD_HELP_SHORT("add a new global variable named <var>, optionally set to <value>\n")
+BAREBOX_CMD_HELP_SHORT("-r to set a value to of all globalvars beginning with 'match'")
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(global)
.cmd = do_global,
- .usage = "create global variables",
+ .usage = "create or set global variables",
BAREBOX_CMD_HELP(cmd_global_help)
BAREBOX_CMD_END
diff --git a/commands/oftree.c b/commands/oftree.c
index 4dc9cd408b..7404db56b1 100644
--- a/commands/oftree.c
+++ b/commands/oftree.c
@@ -45,7 +45,8 @@ static int do_oftree(int argc, char *argv[])
char *file = NULL;
const char *node = "/";
int dump = 0;
- int parse = 0;
+ int probe = 0;
+ int ret;
while ((opt = getopt(argc, argv, "dpfn:")) > 0) {
switch (opt) {
@@ -53,7 +54,12 @@ static int do_oftree(int argc, char *argv[])
dump = 1;
break;
case 'p':
- parse = 1;
+ if (IS_ENABLED(CONFIG_CMD_OFTREE_PROBE)) {
+ probe = 1;
+ } else {
+ printf("oftree device probe support disabled\n");
+ return COMMAND_ERROR_USAGE;
+ }
break;
case 'f':
free(barebox_fdt);
@@ -68,7 +74,7 @@ static int do_oftree(int argc, char *argv[])
if (optind < argc)
file = argv[optind];
- if (!dump && !parse)
+ if (!dump && !probe)
return COMMAND_ERROR_USAGE;
if (dump) {
@@ -92,7 +98,7 @@ static int do_oftree(int argc, char *argv[])
return 0;
}
- if (parse) {
+ if (probe) {
if (!file)
return COMMAND_ERROR_USAGE;
@@ -102,17 +108,13 @@ static int do_oftree(int argc, char *argv[])
return 1;
}
- fdt = xrealloc(fdt, size + 0x8000);
- fdt_open_into(fdt, fdt, size + 0x8000);
- if (!fdt) {
- printf("unable to read %s\n", file);
+ ret = of_parse_dtb(fdt);
+ if (ret) {
+ printf("parse oftree: %s\n", strerror(-ret));
return 1;
}
- if (barebox_fdt)
- free(barebox_fdt);
-
- barebox_fdt = fdt;
+ of_probe();
}
return 0;
@@ -120,7 +122,7 @@ static int do_oftree(int argc, char *argv[])
BAREBOX_CMD_HELP_START(oftree)
BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS]\n")
-BAREBOX_CMD_HELP_OPT ("-p <FILE>", "parse and store oftree from <file>\n")
+BAREBOX_CMD_HELP_OPT ("-p <FILE>", "probe devices in oftree from <file>\n")
BAREBOX_CMD_HELP_OPT ("-d [FILE]", "dump oftree from [FILE] or the parsed tree if no file is given\n")
BAREBOX_CMD_HELP_OPT ("-f", "free stored oftree\n")
BAREBOX_CMD_HELP_END
diff --git a/commands/splash.c b/commands/splash.c
new file mode 100644
index 0000000000..f40e3e1ec7
--- /dev/null
+++ b/commands/splash.c
@@ -0,0 +1,133 @@
+#include <common.h>
+#include <command.h>
+#include <fs.h>
+#include <linux/stat.h>
+#include <errno.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <fb.h>
+#include <image_renderer.h>
+#include <graphic_utils.h>
+
+static int do_splash(int argc, char *argv[])
+{
+ int ret, opt, fd;
+ char *fbdev = "/dev/fb0";
+ void *fb;
+ struct fb_info info;
+ char *image_file;
+ int startx = -1, starty = -1;
+ int xres, yres;
+ int offscreen = 0;
+ u32 bg_color = 0x00000000;
+ bool do_bg = false;
+ void *offscreenbuf = NULL;
+
+ while((opt = getopt(argc, argv, "f:x:y:ob:")) > 0) {
+ switch(opt) {
+ case 'f':
+ fbdev = optarg;
+ break;
+ case 'b':
+ bg_color = simple_strtoul(optarg, NULL, 0);
+ do_bg = true;
+ break;
+ case 'x':
+ startx = simple_strtoul(optarg, NULL, 0);
+ break;
+ case 'y':
+ starty = simple_strtoul(optarg, NULL, 0);
+ case 'o':
+ offscreen = 1;
+ }
+ }
+
+ if (optind == argc) {
+ printf("no filename given\n");
+ return 1;
+ }
+ image_file = argv[optind];
+
+ fd = open(fbdev, O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ fb = memmap(fd, PROT_READ | PROT_WRITE);
+ if (fb == (void *)-1) {
+ perror("memmap");
+ goto failed_memmap;
+ }
+
+ ret = ioctl(fd, FBIOGET_SCREENINFO, &info);
+ if (ret) {
+ perror("ioctl");
+ goto failed_memmap;
+ }
+
+ xres = info.xres;
+ yres = info.yres;
+
+ if (offscreen) {
+ int fbsize;
+ /* Don't fail if malloc fails, just continue rendering directly
+ * on the framebuffer
+ */
+
+ fbsize = xres * yres * (info.bits_per_pixel >> 3);
+ offscreenbuf = malloc(fbsize);
+ if (offscreenbuf) {
+ if (do_bg)
+ memset_pixel(&info, offscreenbuf, bg_color, xres * yres);
+ else
+ memcpy(offscreenbuf, fb, fbsize);
+ }
+ } else if (do_bg) {
+ memset_pixel(&info, fb, bg_color, xres * yres);
+ }
+
+ if (image_renderer_file(&info, image_file, fb, startx, starty,
+ offscreenbuf) < 0)
+ ret = 1;
+
+ if (offscreenbuf)
+ free(offscreenbuf);
+
+ close(fd);
+
+ return ret;
+
+failed_memmap:
+ close(fd);
+
+ return 1;
+}
+
+BAREBOX_CMD_HELP_START(splash)
+BAREBOX_CMD_HELP_USAGE("splash [OPTIONS] FILE\n")
+BAREBOX_CMD_HELP_SHORT("Show the bitmap FILE on the framebuffer.\n")
+BAREBOX_CMD_HELP_OPT ("-f <fb>", "framebuffer device (/dev/fb0)\n")
+BAREBOX_CMD_HELP_OPT ("-x <xofs>", "x offset (default center)\n")
+BAREBOX_CMD_HELP_OPT ("-y <yofs>", "y offset (default center)\n")
+BAREBOX_CMD_HELP_OPT ("-b <color>", "background color in 0xttrrggbb\n")
+BAREBOX_CMD_HELP_OPT ("-o", "render offscreen\n")
+BAREBOX_CMD_HELP_END
+
+/**
+ * @page bmp_command
+
+This command displays a graphics in the bitmap (.bmp) format on the
+framebuffer. Currently the bmp command supports images with 8 and 24 bit
+color depth.
+
+\todo What does the -o (offscreen) option do?
+
+ */
+
+BAREBOX_CMD_START(splash)
+ .cmd = do_splash,
+ .usage = "show a bmp image",
+ BAREBOX_CMD_HELP(cmd_splash_help)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index b97392cfdb..0597c9cb62 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -96,6 +96,10 @@ config BANNER
bool "display banner"
default y
+config MEMINFO
+ bool "display memory info"
+ default y
+
config ENVIRONMENT_VARIABLES
bool "environment variables support"
@@ -575,6 +579,7 @@ config DEFAULT_ENVIRONMENT_GENERIC
select CMD_CRC
select CMD_CRC_CMP
select CMD_AUTOMOUNT if HAVE_DEFAULT_ENVIRONMENT_NEW
+ select CMD_GLOBAL
prompt "Default environment generic"
help
With this option barebox will use the generic default
diff --git a/common/Makefile b/common/Makefile
index df9f301234..68582b78e1 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MALLOC_TLSF) += tlsf.o
obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o
obj-y += clock.o
obj-$(CONFIG_BANNER) += version.o
+obj-$(CONFIG_MEMINFO) += meminfo.o
obj-$(CONFIG_COMMAND_SUPPORT) += command.o
obj-$(CONFIG_CONSOLE_FULL) += console.o
obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
diff --git a/common/filetype.c b/common/filetype.c
index c1b24cdd3a..f37370e457 100644
--- a/common/filetype.c
+++ b/common/filetype.c
@@ -22,6 +22,7 @@
#include <fcntl.h>
#include <fs.h>
#include <malloc.h>
+#include <errno.h>
static const char *filetype_str[] = {
[filetype_unknown] = "unknown",
@@ -38,6 +39,9 @@ static const char *filetype_str[] = {
[filetype_sh] = "Bourne Shell",
[filetype_mips_barebox] = "MIPS barebox image",
[filetype_fat] = "FAT filesytem",
+ [filetype_mbr] = "MBR sector",
+ [filetype_bmp] = "BMP image",
+ [filetype_png] = "PNG image",
};
const char *file_type_to_string(enum filetype f)
@@ -48,30 +52,56 @@ const char *file_type_to_string(enum filetype f)
return NULL;
}
-static int is_fat(u8 *buf)
+#define MBR_StartSector 8 /* MBR: Offset of Starting Sector in Partition Table Entry */
+#define BS_55AA 510 /* Boot sector signature (2) */
+#define MBR_Table 446 /* MBR: Partition table offset (2) */
+#define BS_FilSysType32 82 /* File system type (1) */
+#define BS_FilSysType 54 /* File system type (1) */
+
+enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec)
{
- if (get_unaligned_le16(&buf[510]) != 0xAA55)
- return 0;
+ /*
+ * bootsec can be used to return index of the first sector in the
+ * first partition
+ */
+ if (bootsec)
+ *bootsec = 0;
+
+ /*
+ * Check record signature (always placed at offset 510 even if the
+ * sector size is > 512)
+ */
+ if (get_unaligned_le16(&sector[BS_55AA]) != 0xAA55)
+ return filetype_unknown;
+
+ /* Check "FAT" string */
+ if ((get_unaligned_le32(&sector[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
+ return filetype_fat;
- /* FAT */
- if ((get_unaligned_le32(&buf[54]) & 0xFFFFFF) == 0x544146)
- return 1;
+ if ((get_unaligned_le32(&sector[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+ return filetype_fat;
- /* FAT32 */
- if ((get_unaligned_le32(&buf[82]) & 0xFFFFFF) == 0x544146)
- return 1;
+ if (bootsec)
+ /*
+ * This must be an MBR, so return the starting sector of the
+ * first partition so we could check if there is a FAT boot
+ * sector there
+ */
+ *bootsec = get_unaligned_le16(&sector[MBR_Table + MBR_StartSector]);
- return 0;
+ return filetype_mbr;
}
enum filetype file_detect_type(void *_buf)
{
u32 *buf = _buf;
+ u64 *buf64 = _buf;
u8 *buf8 = _buf;
+ enum filetype type;
if (strncmp(buf8, "#!/bin/sh", 9) == 0)
return filetype_sh;
- if (buf[8] == 0x65726162 && buf[9] == 0x00786f62)
+ if (is_barebox_arm_head(_buf))
return filetype_arm_barebox;
if (buf[9] == 0x016f2818 || buf[9] == 0x18286f01)
return filetype_arm_zimage;
@@ -95,8 +125,13 @@ enum filetype file_detect_type(void *_buf)
return filetype_aimage;
if (strncmp(buf8 + 0x10, "barebox", 7) == 0)
return filetype_mips_barebox;
- if (is_fat(buf8))
- return filetype_fat;
+ type = is_fat_or_mbr(buf8, NULL);
+ if (type != filetype_unknown)
+ return type;
+ if (strncmp(buf8, "BM", 2) == 0)
+ return filetype_bmp;
+ if (buf64[0] == le64_to_cpu(0x0a1a0a0d474e5089ull))
+ return filetype_png;
return filetype_unknown;
}
@@ -106,6 +141,7 @@ enum filetype file_name_detect_type(const char *filename)
int fd, ret;
void *buf;
enum filetype type = filetype_unknown;
+ unsigned long bootsec;
fd = open(filename, O_RDONLY);
if (fd < 0)
@@ -119,6 +155,21 @@ enum filetype file_name_detect_type(const char *filename)
type = file_detect_type(buf);
+ if (type == filetype_mbr) {
+ /*
+ * Get the first partition start sector
+ * and check for FAT in it
+ */
+ is_fat_or_mbr(buf, &bootsec);
+ ret = lseek(fd, (bootsec) * 512, SEEK_SET);
+ if (ret < 0)
+ goto err_out;
+ ret = read(fd, buf, 512);
+ if (ret < 0)
+ goto err_out;
+ type = is_fat_or_mbr((u8 *)buf, NULL);
+ }
+
err_out:
close(fd);
free(buf);
diff --git a/common/globalvar.c b/common/globalvar.c
index 71296ff5a3..a8aaa72553 100644
--- a/common/globalvar.c
+++ b/common/globalvar.c
@@ -46,6 +46,16 @@ char *globalvar_get_match(const char *match, const char *seperator)
return val;
}
+void globalvar_set_match(const char *match, const char *val)
+{
+ struct param_d *param;
+
+ list_for_each_entry(param, &global_device.parameters, list) {
+ if (!strncmp(match, param->name, strlen(match)))
+ dev_set_param(&global_device, param->name, val);
+ }
+}
+
/*
* globalvar_add_simple
*
diff --git a/common/image.c b/common/image.c
index 3f6d49726c..9252d5e775 100644
--- a/common/image.c
+++ b/common/image.c
@@ -57,6 +57,8 @@ static table_entry_t arch_name[] = {
{ IH_ARCH_SPARC64, "sparc64", "SPARC 64 Bit", },
{ IH_ARCH_BLACKFIN, "blackfin", "Blackfin", },
{ IH_ARCH_AVR32, "avr32", "AVR32", },
+ { IH_ARCH_NDS32, "nds32", "NDS32", },
+ { IH_ARCH_OPENRISC, "or1k", "OpenRISC 1000",},
{ -1, "", "", },
};
diff --git a/common/meminfo.c b/common/meminfo.c
new file mode 100644
index 0000000000..06fce5afb4
--- /dev/null
+++ b/common/meminfo.c
@@ -0,0 +1,23 @@
+#include <common.h>
+#include <init.h>
+#include <memory.h>
+#include <asm-generic/memory_layout.h>
+
+static int display_meminfo(void)
+{
+ ulong mstart = mem_malloc_start();
+ ulong mend = mem_malloc_end();
+ ulong msize = mend - mstart + 1;
+
+ debug("barebox code: 0x%p -> 0x%p\n", _stext, _etext);
+ debug("bss segment: 0x%p -> 0x%p\n", __bss_start, __bss_stop);
+ printf("malloc space: 0x%08lx -> 0x%08lx (size %s)\n",
+ mstart, mend, size_human_readable(msize));
+#ifdef CONFIG_ARM
+ printf("stack space: 0x%08x -> 0x%08x (size %s)\n",
+ STACK_BASE, STACK_BASE + STACK_SIZE,
+ size_human_readable(STACK_SIZE));
+#endif
+ return 0;
+}
+late_initcall(display_meminfo);
diff --git a/common/oftree.c b/common/oftree.c
index 677e934a98..3e8c6f8c65 100644
--- a/common/oftree.c
+++ b/common/oftree.c
@@ -57,7 +57,7 @@ static int is_printable_string(const void *data, int len)
* a string, concatenated strings, a byte, word, double word, or (if all
* else fails) it is printed as a stream of bytes.
*/
-static void print_data(const void *data, int len)
+void of_print_property(const void *data, int len)
{
int j;
@@ -169,7 +169,7 @@ int fdt_print(struct fdt_header *working_fdt, const char *pathp)
printf_indent(level, "%s;\n", pathp);
} else {
printf_indent(level, "%s = ", pathp);
- print_data(nodep, len);
+ of_print_property(nodep, len);
printf(";\n");
}
break;
diff --git a/common/startup.c b/common/startup.c
index b13fbe466b..b53bbef840 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -29,34 +29,15 @@
#include <init.h>
#include <command.h>
#include <malloc.h>
-#include <memory.h>
#include <debug_ll.h>
#include <fs.h>
#include <linux/stat.h>
#include <environment.h>
-#include <asm-generic/memory_layout.h>
#include <asm/sections.h>
extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
__barebox_initcalls_end[];
-static void display_meminfo(void)
-{
- ulong mstart = mem_malloc_start();
- ulong mend = mem_malloc_end();
- ulong msize = mend - mstart + 1;
-
- debug("barebox code: 0x%p -> 0x%p\n", _stext, _etext);
- debug("bss segment: 0x%p -> 0x%p\n", __bss_start, __bss_stop);
- printf("Malloc space: 0x%08lx -> 0x%08lx (size %s)\n",
- mstart, mend, size_human_readable(msize));
-#ifdef CONFIG_ARM
- printf("Stack space : 0x%08x -> 0x%08x (size %s)\n",
- STACK_BASE, STACK_BASE + STACK_SIZE,
- size_human_readable(STACK_SIZE));
-#endif
-}
-
#ifdef CONFIG_DEFAULT_ENVIRONMENT
#include <generated/barebox_default_env.h>
@@ -124,8 +105,6 @@ void start_barebox (void)
debug("initcalls done\n");
- display_meminfo();
-
#ifdef CONFIG_ENV_HANDLING
if (envfs_load(default_environment_path, "/env")) {
#ifdef CONFIG_DEFAULT_ENVIRONMENT
diff --git a/defaultenv-2/base/bin/boot b/defaultenv-2/base/bin/boot
index 4ebda3f4b2..103eb8767e 100644
--- a/defaultenv-2/base/bin/boot
+++ b/defaultenv-2/base/bin/boot
@@ -33,6 +33,10 @@ while getopt "vdhl" opt; do
fi
done
+# clear linux.bootargs.dyn.* and bootm.*
+global -r linux.bootargs.dyn.
+global -r bootm.
+
if [ $# = 0 ]; then
scr="$global.boot.default"
else
diff --git a/defaultenv-2/base/bin/bootargs-ip b/defaultenv-2/base/bin/bootargs-ip
index 15041c6359..2d4486caf8 100644
--- a/defaultenv-2/base/bin/bootargs-ip
+++ b/defaultenv-2/base/bin/bootargs-ip
@@ -5,7 +5,7 @@
. /env/network/eth0
if [ $ip = dhcp ]; then
- global.linux.bootargs.ip="ip=dhcp"
+ global.linux.bootargs.dyn.ip="ip=dhcp"
else
- global.linux.bootargs.ip="ip=$ipaddr:$serverip:$gateway:$netmask::eth0:"
+ global.linux.bootargs.dyn.ip="ip=$ipaddr:$serverip:$gateway:$netmask::eth0:"
fi
diff --git a/defaultenv-2/base/bin/bootargs-ip-barebox b/defaultenv-2/base/bin/bootargs-ip-barebox
index 986c142286..5a3b984069 100644
--- a/defaultenv-2/base/bin/bootargs-ip-barebox
+++ b/defaultenv-2/base/bin/bootargs-ip-barebox
@@ -4,4 +4,4 @@
ifup eth0
-global.linux.bootargs.ip="ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask::eth0:"
+global.linux.bootargs.dyn.ip="ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask::eth0:"
diff --git a/defaultenv-2/base/bin/bootargs-ip-dhcp b/defaultenv-2/base/bin/bootargs-ip-dhcp
index c542b248f0..dec8ae452a 100644
--- a/defaultenv-2/base/bin/bootargs-ip-dhcp
+++ b/defaultenv-2/base/bin/bootargs-ip-dhcp
@@ -2,4 +2,4 @@
# Do dhcp in Linux
-global.linux.bootargs.ip="ip=dhcp"
+global.linux.bootargs.dyn.ip="ip=dhcp"
diff --git a/defaultenv-2/base/bin/bootargs-ip-none b/defaultenv-2/base/bin/bootargs-ip-none
index c010154650..88aaa21a78 100644
--- a/defaultenv-2/base/bin/bootargs-ip-none
+++ b/defaultenv-2/base/bin/bootargs-ip-none
@@ -2,4 +2,4 @@
# disable ip setup in Linux
-global.linux.bootargs.ip="ip=none"
+global.linux.bootargs.dyn.ip="ip=none"
diff --git a/defaultenv-2/base/bin/bootargs-root-disk b/defaultenv-2/base/bin/bootargs-root-disk
index df8750e46d..aa60cf33f0 100644
--- a/defaultenv-2/base/bin/bootargs-root-disk
+++ b/defaultenv-2/base/bin/bootargs-root-disk
@@ -23,4 +23,4 @@ if [ -z "${fstype}" ]; then
exit 1
fi
-global.linux.bootargs.root="root=/dev/$part rootfstype=$fstype rootwait"
+global.linux.bootargs.dyn.root="root=/dev/$part rootfstype=$fstype rootwait"
diff --git a/defaultenv-2/base/bin/bootargs-root-ext b/defaultenv-2/base/bin/bootargs-root-ext
index 45fcd5acfb..dbdddb9fcc 100644
--- a/defaultenv-2/base/bin/bootargs-root-ext
+++ b/defaultenv-2/base/bin/bootargs-root-ext
@@ -9,4 +9,4 @@ while getopt "m:r:" opt; do
fi
done
-global.linux.bootargs.root="root=/dev/$part rootfstype=ext$type rootwait"
+global.linux.bootargs.dyn.root="root=/dev/$part rootfstype=ext$type rootwait"
diff --git a/defaultenv-2/base/bin/bootargs-root-initrd b/defaultenv-2/base/bin/bootargs-root-initrd
index 7072cea65b..cc711a1051 100644
--- a/defaultenv-2/base/bin/bootargs-root-initrd
+++ b/defaultenv-2/base/bin/bootargs-root-initrd
@@ -13,4 +13,4 @@ while getopt "i:h" opt; do
fi
done
-global.linux.bootargs.root="root=/dev/ram0 rdinit=${rdinit}"
+global.linux.bootargs.dyn.root="root=/dev/ram0 rdinit=${rdinit}"
diff --git a/defaultenv-2/base/bin/bootargs-root-jffs2 b/defaultenv-2/base/bin/bootargs-root-jffs2
index 74d59afe39..a8eb5e7bb8 100644
--- a/defaultenv-2/base/bin/bootargs-root-jffs2
+++ b/defaultenv-2/base/bin/bootargs-root-jffs2
@@ -18,4 +18,4 @@ if [ -z "$mtd" ]; then
exit 1
fi
-global.linux.bootargs.root="root=$mtd rootfstype=jffs2"
+global.linux.bootargs.dyn.root="root=$mtd rootfstype=jffs2"
diff --git a/defaultenv-2/base/bin/bootargs-root-nfs b/defaultenv-2/base/bin/bootargs-root-nfs
index 27bb6c40fa..355f93dbe3 100644
--- a/defaultenv-2/base/bin/bootargs-root-nfs
+++ b/defaultenv-2/base/bin/bootargs-root-nfs
@@ -17,4 +17,4 @@ if [ -n ${serverip} ]; then
nfsroot="$serverip:$nfsroot"
fi
-global.linux.bootargs.root="root=/dev/nfs nfsroot=$nfsroot,v3,tcp"
+global.linux.bootargs.dyn.root="root=/dev/nfs nfsroot=$nfsroot,v3,tcp"
diff --git a/defaultenv-2/base/bin/bootargs-root-ubi b/defaultenv-2/base/bin/bootargs-root-ubi
index fb7f328bef..4260336915 100644
--- a/defaultenv-2/base/bin/bootargs-root-ubi
+++ b/defaultenv-2/base/bin/bootargs-root-ubi
@@ -21,4 +21,4 @@ if [ -z "$mtd" ]; then
exit 1
fi
-global.linux.bootargs.root="root=ubi0:$ubiroot ubi.mtd=$mtd rootfstype=ubifs"
+global.linux.bootargs.dyn.root="root=ubi0:$ubiroot ubi.mtd=$mtd rootfstype=ubifs"
diff --git a/defaultenv-2/base/bin/init b/defaultenv-2/base/bin/init
index 9d7eb2eea7..8e8871d10a 100644
--- a/defaultenv-2/base/bin/init
+++ b/defaultenv-2/base/bin/init
@@ -8,8 +8,9 @@ global autoboot_timeout=3
global boot.default=net
global allow_color=true
global linux.bootargs.base
-global linux.bootargs.ip
-global linux.bootargs.root
+#linux.bootargs.dyn.* will be clearer at the beginning of boot
+global linux.bootargs.dyn.ip
+global linux.bootargs.dyn.root
global editcmd=sedit
/env/init/general
diff --git a/defaultenv-2/base/boot/initrd b/defaultenv-2/base/boot/initrd
index 79a353a10a..7c44d07a6e 100644
--- a/defaultenv-2/base/boot/initrd
+++ b/defaultenv-2/base/boot/initrd
@@ -11,7 +11,7 @@ global.bootm.initrd="${path}/initramfs"
bootargs-root-initrd
#global.bootm.oftree=<path to oftree>
-global.linux.bootargs.root="root=/dev/ram0"
+global.linux.bootargs.dyn.root="root=/dev/ram0"
#bootargs-root-nfs -n "<path on server>" -s <serverip>
#bootargs-root-ubi -r <volume> -m <mtdname>
diff --git a/defaultenv-2/base/data/ansi-colors b/defaultenv-2/base/data/ansi-colors
index c71b6b7998..636532979a 100644
--- a/defaultenv-2/base/data/ansi-colors
+++ b/defaultenv-2/base/data/ansi-colors
@@ -1,5 +1,9 @@
#!/bin/sh
+if [ ${global.allow_color} != "true" ]; then
+ exit
+fi
+
# Colors
export RED='\e[1;31m'
export BLUE='\e[1;34m'
diff --git a/defaultenv-2/base/network/eth0 b/defaultenv-2/base/network/eth0
index 048a288245..7e731cae00 100644
--- a/defaultenv-2/base/network/eth0
+++ b/defaultenv-2/base/network/eth0
@@ -2,6 +2,7 @@
# ip setting (static/dhcp)
ip=dhcp
+global.dhcp.vendor_id=barebox-${global.hostname}
# static setup used if ip=static
ipaddr=
diff --git a/defaultenv-2/menu/menu/mainmenu b/defaultenv-2/menu/menu/mainmenu
index d7b0033220..5bd7027e2a 100644
--- a/defaultenv-2/menu/menu/mainmenu
+++ b/defaultenv-2/menu/menu/mainmenu
@@ -3,9 +3,7 @@
savepath=$PATH
export menupath=$PATH:/env/menu
-if [ ${global.allow_color} = "true" ]; then
- . /env/data/ansi-colors
-fi
+. /env/data/ansi-colors
while true; do
export PATH=${menupath}
diff --git a/defaultenv/bin/boot b/defaultenv/bin/boot
index 61b893a724..c17ccdb8f5 100644
--- a/defaultenv/bin/boot
+++ b/defaultenv/bin/boot
@@ -44,14 +44,14 @@ fi
if [ x$ip = xdhcp -o x$ip = "xdhcp-barebox" ]; then
if [ x$kernel_loc = xnfs -o x$kernel_loc = xtftp ]; then
dhcp
- if [ x$rootpath != x ]; then
- nfsroot=$rootpath
+ if [ x${global.dhcp.rootpath} != x ]; then
+ nfsroot=${global.dhcp.rootpath}
fi
- if [ x$bootfile != x ]; then
- kernelimage=$bootfile
+ if [ x${global.dhcp.bootfile} != x ]; then
+ kernelimage=${global.dhcp.bootfile}
fi
- if [ x$dhcp_oftree_file != x ]; then
- oftreeimage=$dhcp_oftree_file
+ if [ x$global.dhcp.oftree_file} != x ]; then
+ oftreeimage=${global.dhcp.oftree_file}
fi
fi
fi
diff --git a/defaultenv/bin/init b/defaultenv/bin/init
index f535e3781c..adb3c43a66 100644
--- a/defaultenv/bin/init
+++ b/defaultenv/bin/init
@@ -3,6 +3,8 @@
PATH=/env/bin
export PATH
+global hostname
+
. /env/config
if [ -e /dev/nor0 -a -n "$nor_parts" ]; then
addpart /dev/nor0 $nor_parts
diff --git a/defaultenv/config b/defaultenv/config
index 7b61d29730..391ba47c18 100644
--- a/defaultenv/config
+++ b/defaultenv/config
@@ -11,7 +11,7 @@ fi
# use 'dhcp' to do dhcp in barebox and in kernel
# use 'none' if you want to skip kernel ip autoconfiguration
ip=dhcp
-dhcp_vendor_id=barebox
+global.dhcp.vendor_id=barebox
# or set your networking parameters here
#eth0.ipaddr=a.b.c.d
@@ -31,25 +31,25 @@ oftree_loc=tftp
rootfs_type=ubifs
# where is the rootfs in case of 'rootfs_loc=disk' (linux name)
rootfs_part_linux_dev=mmcblk0p4
-rootfsimage=rootfs-${hostname}.$rootfs_type
+rootfsimage=rootfs-${global.hostname}.$rootfs_type
# where is the kernel image in case of 'kernel_loc=disk'
kernel_part=disk0.2
-kernelimage=zImage-$hostname
-#kernelimage=uImage-$hostname
-#kernelimage=Image-$hostname
-#kernelimage=Image-$hostname.lzo
+kernelimage=zImage-${global.hostname}
+#kernelimage=uImage-${global.hostname}
+#kernelimage=Image-${global.hostname}
+#kernelimage=Image-${global.hostname}.lzo
-bareboximage=barebox-${hostname}.bin
-bareboxenvimage=barebox-${hostname}.bin
+bareboximage=barebox-${global.hostname}.bin
+bareboxenvimage=barebox-${global.hostname}.bin
if [ -n $user ]; then
bareboximage="$user"-"$bareboximage"
bareboxenvimage="$user"-"$bareboxenvimage"
kernelimage="$user"-"$kernelimage"
rootfsimage="$user"-"$rootfsimage"
- nfsroot="/home/$user/nfsroot/$hostname"
+ nfsroot="/home/$user/nfsroot/${global.hostname}"
else
nfsroot="/path/to/nfs/root"
fi
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 70797c182c..d0b5e3abdb 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -20,5 +20,6 @@ source "drivers/watchdog/Kconfig"
source "drivers/pwm/Kconfig"
source "drivers/dma/Kconfig"
source "drivers/gpio/Kconfig"
+source "drivers/of/Kconfig"
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 28a5cb8f35..2a1f8b0f23 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,4 +1,5 @@
obj-y += base/
+obj-$(CONFIG_ARM_AMBA) += amba/
obj-y += net/
obj-y += serial/
obj-y += mtd/
@@ -19,3 +20,4 @@ obj-y += misc/
obj-y += dma/
obj-y += watchdog/
obj-y += gpio/
+obj-$(CONFIG_OFDEVICE) += of/
diff --git a/drivers/amba/Makefile b/drivers/amba/Makefile
new file mode 100644
index 0000000000..a4a511b322
--- /dev/null
+++ b/drivers/amba/Makefile
@@ -0,0 +1,2 @@
+
+obj-y += bus.o
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
new file mode 100644
index 0000000000..383c77ee13
--- /dev/null
+++ b/drivers/amba/bus.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
+ * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2.
+ */
+#include <common.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <linux/amba/bus.h>
+#include <io.h>
+
+#define to_amba_driver(d) container_of(d, struct amba_driver, drv)
+
+static const struct amba_id *
+amba_lookup(const struct amba_id *table, struct amba_device *dev)
+{
+ int ret = 0;
+
+ while (table->mask) {
+ ret = (dev->periphid & table->mask) == table->id;
+ if (ret)
+ break;
+ table++;
+ }
+
+ return ret ? table : NULL;
+}
+
+static int amba_match(struct device_d *dev, struct driver_d *drv)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+
+ struct amba_driver *pcdrv = to_amba_driver(drv);
+
+ return amba_lookup(pcdrv->id_table, pcdev) == NULL;
+}
+
+static int amba_get_enable_pclk(struct amba_device *pcdev)
+{
+ struct clk *pclk = clk_get(&pcdev->dev, "apb_pclk");
+ int ret;
+
+ pcdev->pclk = pclk;
+
+ if (IS_ERR(pclk))
+ return PTR_ERR(pclk);
+
+ ret = clk_enable(pclk);
+ if (ret) {
+ clk_put(pclk);
+ }
+
+ return ret;
+}
+
+static int amba_probe(struct device_d *dev)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+ struct amba_driver *pcdrv = to_amba_driver(dev->driver);
+ const struct amba_id *id = amba_lookup(pcdrv->id_table, pcdev);
+
+ return pcdrv->probe(pcdev, id);
+}
+
+static void amba_remove(struct device_d *dev)
+{
+ struct amba_device *pcdev = to_amba_device(dev);
+ struct amba_driver *drv = to_amba_driver(dev->driver);
+
+ drv->remove(pcdev);
+}
+
+struct bus_type amba_bustype = {
+ .name = "amba",
+ .match = amba_match,
+ .probe = amba_probe,
+ .remove = amba_remove,
+};
+
+int amba_driver_register(struct amba_driver *drv)
+{
+ drv->drv.bus = &amba_bustype;
+
+ if (drv->probe)
+ drv->drv.probe = amba_probe;
+ if (drv->remove)
+ drv->drv.remove = amba_remove;
+
+ return register_driver(&drv->drv);
+}
+
+/**
+ * amba_device_add - add a previously allocated AMBA device structure
+ * @dev: AMBA device allocated by amba_device_alloc
+ * @parent: resource parent for this devices resources
+ *
+ * Claim the resource, and read the device cell ID if not already
+ * initialized. Register the AMBA device with the Linux device
+ * manager.
+ */
+int amba_device_add(struct amba_device *dev)
+{
+ u32 size;
+ void __iomem *tmp;
+ int i, ret;
+ struct resource *res = NULL;
+
+ dev->dev.bus = &amba_bustype;
+
+ /*
+ * Dynamically calculate the size of the resource
+ * and use this for iomap
+ */
+ size = resource_size(&dev->res);
+ res = request_iomem_region("amba", dev->res.start, dev->res.end);
+ if (!res)
+ return -ENOMEM;
+ dev->base = tmp = (void __force __iomem *)res->start;
+ if (!tmp) {
+ ret = -ENOMEM;
+ goto err_release;
+ }
+
+ /* Hard-coded primecell ID instead of plug-n-play */
+ if (dev->periphid != 0)
+ goto skip_probe;
+
+ ret = amba_get_enable_pclk(dev);
+ if (ret == 0) {
+ u32 pid, cid;
+
+ /*
+ * Read pid and cid based on size of resource
+ * they are located at end of region
+ */
+ for (pid = 0, i = 0; i < 4; i++)
+ pid |= (readl(tmp + size - 0x20 + 4 * i) & 255) <<
+ (i * 8);
+ for (cid = 0, i = 0; i < 4; i++)
+ cid |= (readl(tmp + size - 0x10 + 4 * i) & 255) <<
+ (i * 8);
+
+ if (cid == AMBA_CID)
+ dev->periphid = pid;
+
+ if (!dev->periphid)
+ ret = -ENODEV;
+ }
+
+ if (ret)
+ goto err_release;
+
+ skip_probe:
+ ret = register_device(&dev->dev);
+ if (ret)
+ goto err_release;
+
+ return ret;
+ err_release:
+ release_region(res);
+ return ret;
+}
+
+struct amba_device *
+amba_aphb_device_add(struct device_d *parent, const char *name, int id,
+ resource_size_t base, size_t size,
+ void *pdata, unsigned int periphid)
+{
+ struct amba_device *dev;
+ int ret;
+
+ dev = amba_device_alloc(name, id, base, size);
+
+ dev->periphid = periphid;
+ dev->dev.platform_data = pdata;
+ dev->dev.parent = parent;
+
+ ret = amba_device_add(dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return dev;
+}
+
+/**
+ * amba_device_alloc - allocate an AMBA device
+ * @name: sysfs name of the AMBA device
+ * @base: base of AMBA device
+ * @size: size of AMBA device
+ *
+ * Allocate and initialize an AMBA device structure. Returns %NULL
+ * on failure.
+ */
+struct amba_device *amba_device_alloc(const char *name, int id, resource_size_t base,
+ size_t size)
+{
+ struct amba_device *dev;
+
+ dev = xzalloc(sizeof(*dev));
+
+ strcpy(dev->dev.name, name);
+ dev->dev.id = id;
+ dev->res.start = base;
+ dev->res.end = base + size - 1;
+ dev->res.flags = IORESOURCE_MEM;
+
+ return dev;
+}
+
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 957ca5ac2a..e1f1c7a0ad 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,3 +1,4 @@
+obj-y += bus.o
obj-y += driver.o
obj-y += platform.o
obj-y += resource.o
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
new file mode 100644
index 0000000000..1dd139f7a3
--- /dev/null
+++ b/drivers/base/bus.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Under GPLv2
+ */
+
+#include <common.h>
+#include <driver.h>
+#include <errno.h>
+
+LIST_HEAD(bus_list);
+EXPORT_SYMBOL(bus_list);
+
+struct bus_type *get_bus_by_name(const char *name)
+{
+ struct bus_type *bus;
+
+ for_each_bus(bus) {
+ if(!strcmp(bus->name, name))
+ return bus;
+ }
+
+ return NULL;
+}
+
+int bus_register(struct bus_type *bus)
+{
+ if (get_bus_by_name(bus->name))
+ return -EEXIST;
+
+ INIT_LIST_HEAD(&bus->device_list);
+ INIT_LIST_HEAD(&bus->driver_list);
+
+ list_add_tail(&bus->list, &bus_list);
+
+ return 0;
+}
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index dc29021738..1def2f85e7 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -82,8 +82,6 @@ static int match(struct driver_d *drv, struct device_d *dev)
dev->driver = drv;
- if (dev->bus != drv->bus)
- goto err_out;
if (dev->bus->match(dev, drv))
goto err_out;
if (dev->bus->probe(dev))
@@ -113,18 +111,29 @@ int register_device(struct device_d *new_device)
debug ("register_device: %s\n", dev_name(new_device));
- if (!new_device->bus) {
-// dev_err(new_device, "no bus type associated. Needs fixup\n");
+ if (!new_device->bus)
new_device->bus = &platform_bus;
+
+ if (new_device->bus == &platform_bus && new_device->resource) {
+ struct device_d *dev;
+
+ bus_for_each_device(new_device->bus, dev) {
+ if (!dev->resource)
+ continue;
+ if (dev->resource->start == new_device->resource->start) {
+ return -EBUSY;
+ }
+ }
}
list_add_tail(&new_device->list, &device_list);
+ list_add_tail(&new_device->bus_list, &new_device->bus->device_list);
INIT_LIST_HEAD(&new_device->children);
INIT_LIST_HEAD(&new_device->cdevs);
INIT_LIST_HEAD(&new_device->parameters);
INIT_LIST_HEAD(&new_device->active);
- for_each_driver(drv) {
+ bus_for_each_driver(new_device->bus, drv) {
if (!match(drv, new_device))
break;
}
@@ -156,6 +165,7 @@ int unregister_device(struct device_d *old_dev)
}
list_del(&old_dev->list);
+ list_del(&old_dev->bus_list);
list_del(&old_dev->active);
/* remove device from parents child list */
@@ -209,13 +219,14 @@ int register_driver(struct driver_d *drv)
}
list_add_tail(&drv->list, &driver_list);
+ list_add_tail(&drv->bus_list, &drv->bus->driver_list);
if (!drv->info)
drv->info = noinfo;
if (!drv->shortinfo)
drv->shortinfo = noshortinfo;
- for_each_device(dev)
+ bus_for_each_device(drv->bus, dev)
match(drv, dev);
return 0;
@@ -310,6 +321,25 @@ const char *dev_id(const struct device_d *dev)
return buf;
}
+int dev_printf(const struct device_d *dev, const char *format, ...)
+{
+ va_list args;
+ int ret = 0;
+
+ if (dev->driver && dev->driver->name)
+ ret += printf("%s ", dev->driver->name);
+
+ ret += printf("%s: ", dev_name(dev));
+
+ va_start(args, format);
+
+ ret += vprintf(format, args);
+
+ va_end(args);
+
+ return ret;
+}
+
void devices_shutdown(void)
{
struct device_d *dev;
@@ -354,6 +384,21 @@ static int do_devinfo_subtree(struct device_d *dev, int depth)
return 0;
}
+int dev_get_drvdata(struct device_d *dev, unsigned long *data)
+{
+ if (dev->of_id_entry) {
+ *data = dev->of_id_entry->data;
+ return 0;
+ }
+
+ if (dev->id_entry) {
+ *data = dev->id_entry->driver_data;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
static int do_devinfo(int argc, char *argv[])
{
struct device_d *dev;
@@ -403,6 +448,12 @@ static int do_devinfo(int argc, char *argv[])
list_for_each_entry(param, &dev->parameters, list)
printf("%16s = %s\n", param->name, dev_get_param(dev, param->name));
+#ifdef CONFIG_OFDEVICE
+ if (dev->device_node) {
+ printf("\ndevice node: %s\n", dev->device_node->full_name);
+ of_print_nodes(dev->device_node, 0);
+ }
+#endif
}
return 0;
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index f1069bc899..d3021ab833 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -18,10 +18,31 @@
*/
#include <common.h>
#include <driver.h>
+#include <errno.h>
+#include <init.h>
static int platform_match(struct device_d *dev, struct driver_d *drv)
{
- return strcmp(dev->name, drv->name) ? -1 : 0;
+ if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node &&
+ drv->of_compatible)
+ return of_match(dev, drv);
+
+ if (!strcmp(dev->name, drv->name))
+ return 0;
+
+ if (drv->id_table) {
+ struct platform_device_id *id = drv->id_table;
+
+ while (id->name) {
+ if (!strcmp(id->name, dev->name)) {
+ dev->id_entry = id;
+ return 0;
+ }
+ id++;
+ }
+ }
+
+ return -1;
}
static int platform_probe(struct device_d *dev)
@@ -41,15 +62,8 @@ struct bus_type platform_bus = {
.remove = platform_remove,
};
-#if 0
-LIST_HEAD(bus_list);
-EXPORT_SYMBOL(bus_list);
-
-int bus_register(struct bus_type *bus)
+static int plarform_init(void)
{
- list_add_tail(&bus->list, &bus_list);
-
- return 0;
+ return bus_register(&platform_bus);
}
-#endif
-
+pure_initcall(plarform_init);
diff --git a/drivers/eeprom/at25.c b/drivers/eeprom/at25.c
index 03d191eb90..5578c783ad 100644
--- a/drivers/eeprom/at25.c
+++ b/drivers/eeprom/at25.c
@@ -312,7 +312,7 @@ static struct driver_d at25_driver = {
static int at25_init(void)
{
- register_driver(&at25_driver);
+ spi_register_driver(&at25_driver);
return 0;
}
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index fa3b041534..118135182d 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -145,7 +145,7 @@ static int stmpe_gpio_probe(struct device_d *dev)
return ret;
}
- dev_info(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base);
+ dev_dbg(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base);
return 0;
}
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
index 3af2b3e66c..27fd256cf7 100644
--- a/drivers/i2c/i2c.c
+++ b/drivers/i2c/i2c.c
@@ -21,6 +21,7 @@
#include <errno.h>
#include <malloc.h>
#include <xfuncs.h>
+#include <init.h>
#include <i2c/i2c.h>
@@ -251,6 +252,7 @@ struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
strcpy(client->dev.name, chip->type);
client->dev.type_data = client;
client->dev.platform_data = chip->platform_data;
+ client->dev.bus = &i2c_bus;
client->adapter = adapter;
client->addr = chip->addr;
@@ -372,3 +374,31 @@ int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
return 0;
}
EXPORT_SYMBOL(i2c_add_numbered_adapter);
+
+static int i2c_match(struct device_d *dev, struct driver_d *drv)
+{
+ return strcmp(dev->name, drv->name) ? -1 : 0;
+}
+
+static int i2c_probe(struct device_d *dev)
+{
+ return dev->driver->probe(dev);
+}
+
+static void i2c_remove(struct device_d *dev)
+{
+ dev->driver->remove(dev);
+}
+
+struct bus_type i2c_bus = {
+ .name = "i2c",
+ .match = i2c_match,
+ .probe = i2c_probe,
+ .remove = i2c_remove,
+};
+
+static int i2c_bus_init(void)
+{
+ return bus_register(&i2c_bus);
+}
+pure_initcall(i2c_bus_init);
diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c
index d78cc01a05..7c12eba5da 100644
--- a/drivers/mci/imx-esdhc.c
+++ b/drivers/mci/imx-esdhc.c
@@ -331,7 +331,7 @@ esdhc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd, struct mci_data *data)
esdhc_write32(&regs->irqstat, -1);
/* Wait for the bus to be idle */
- ret = wait_on_timeout(100 * MSECOND,
+ ret = wait_on_timeout(SECOND,
!(esdhc_read32(&regs->prsstat) &
(PRSSTAT_CICHB | PRSSTAT_CIDHB)));
if (ret) {
@@ -563,16 +563,28 @@ static int fsl_esdhc_probe(struct device_d *dev)
return 0;
}
+static __maybe_unused struct of_device_id fsl_esdhc_compatible[] = {
+ {
+ .compatible = "fsl,imx51-esdhc",
+ }, {
+ .compatible = "fsl,imx53-esdhc",
+ }, {
+ .compatible = "fsl,imx6q-usdhc",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d fsl_esdhc_driver = {
- .name = "imx-esdhc",
- .probe = fsl_esdhc_probe,
+ .name = "imx-esdhc",
+ .probe = fsl_esdhc_probe,
+ .of_compatible = DRV_OF_COMPAT(fsl_esdhc_compatible),
};
static int fsl_esdhc_init_driver(void)
{
- register_driver(&fsl_esdhc_driver);
- return 0;
+ register_driver(&fsl_esdhc_driver);
+ return 0;
}
device_initcall(fsl_esdhc_init_driver);
-
diff --git a/drivers/mci/mci_spi.c b/drivers/mci/mci_spi.c
index 35b454751f..5894104231 100644
--- a/drivers/mci/mci_spi.c
+++ b/drivers/mci/mci_spi.c
@@ -178,7 +178,7 @@ static uint mmc_spi_readdata(struct mmc_spi_host *host, void *xbuf,
mmc_spi_readbytes(host, bsize, buf);
mmc_spi_readbytes(host, 2, &crc);
#ifdef CONFIG_MMC_SPI_CRC_ON
- if (swab16(cyg_crc16(buf, bsize)) != crc) {
+ if (be16_to_cpu(cyg_crc16(buf, bsize)) != crc) {
dev_dbg(host->dev, "%s: CRC error\n", __func__);
r1 = R1_SPI_COM_CRC;
break;
@@ -209,7 +209,7 @@ static uint mmc_spi_writedata(struct mmc_spi_host *host, const void *xbuf,
while (bcnt--) {
#ifdef CONFIG_MMC_SPI_CRC_ON
- crc = swab16(cyg_crc16((u8 *)buf, bsize));
+ crc = be16_to_cpu(cyg_crc16((u8 *)buf, bsize));
#endif
mmc_spi_writebytes(host, 2, tok);
mmc_spi_writebytes(host, bsize, (void *)buf);
@@ -288,7 +288,7 @@ static int mmc_spi_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci
} else if (cmd->resp_type == MMC_RSP_R2) {
r1 = mmc_spi_readdata(host, cmd->response, 1, 16);
for (i = 0; i < 4; i++)
- cmd->response[i] = swab32(cmd->response[i]);
+ cmd->response[i] = be32_to_cpu(cmd->response[i]);
dev_dbg(host->dev, "MMC_RSP_R2 -> %x %x %x %x\n", cmd->response[0], cmd->response[1],
cmd->response[2], cmd->response[3]);
} else if (!data) {
@@ -296,7 +296,7 @@ static int mmc_spi_request(struct mci_host *mci, struct mci_cmd *cmd, struct mci
case SD_CMD_SEND_IF_COND:
case MMC_CMD_SPI_READ_OCR:
mmc_spi_readbytes(host, 4, cmd->response);
- cmd->response[0] = swab32(cmd->response[0]);
+ cmd->response[0] = be32_to_cpu(cmd->response[0]);
break;
}
} else {
@@ -420,7 +420,7 @@ static struct driver_d spi_mci_driver = {
static int spi_mci_init_driver(void)
{
- register_driver(&spi_mci_driver);
+ spi_register_driver(&spi_mci_driver);
return 0;
}
diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c
index 00bfc79765..eba1a6aedf 100644
--- a/drivers/mci/omap_hsmmc.c
+++ b/drivers/mci/omap_hsmmc.c
@@ -234,7 +234,7 @@ static int mmc_init_setup(struct mci_host *mci, struct device_d *dev)
start = get_time_ns();
while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
if (is_timeout(start, SECOND)) {
- dev_dbg(hsmmc->dev, "timedout waiting for cc2!\n");
+ dev_dbg(hsmmc->dev, "timeout waiting for reset done\n");
return -ETIMEDOUT;
}
}
diff --git a/drivers/mfd/lp3972.c b/drivers/mfd/lp3972.c
index 9d12717b56..082ecaa54b 100644
--- a/drivers/mfd/lp3972.c
+++ b/drivers/mfd/lp3972.c
@@ -99,7 +99,7 @@ static struct driver_d lp_driver = {
static int lp_init(void)
{
- register_driver(&lp_driver);
+ i2c_register_driver(&lp_driver);
return 0;
}
diff --git a/drivers/mfd/mc13xxx.c b/drivers/mfd/mc13xxx.c
index a6a9655886..d6cf73cba8 100644
--- a/drivers/mfd/mc13xxx.c
+++ b/drivers/mfd/mc13xxx.c
@@ -332,31 +332,51 @@ static int mc_probe(struct device_d *dev, enum mc13xxx_mode mode)
return 0;
}
+static __maybe_unused struct of_device_id mc13892_dt_ids[] = {
+ {
+ .compatible = "fsl,mc13892",
+ }, {
+ .compatible = "fsl,mc13783",
+ }, {
+ /* sentinel */
+ }
+};
+
+#ifdef CONFIG_I2C
static int mc_i2c_probe(struct device_d *dev)
{
return mc_probe(dev, MC13XXX_MODE_I2C);
}
-static int mc_spi_probe(struct device_d *dev)
-{
- return mc_probe(dev, MC13XXX_MODE_SPI);
-}
-
static struct driver_d mc_i2c_driver = {
.name = "mc13xxx-i2c",
.probe = mc_i2c_probe,
+ .of_compatible = DRV_OF_COMPAT(mc13892_dt_ids),
};
+static int mc_i2c_init(void)
+{
+ return i2c_register_driver(&mc_i2c_driver);
+}
+device_initcall(mc_i2c_init);
+#endif
+
+#ifdef CONFIG_SPI
+static int mc_spi_probe(struct device_d *dev)
+{
+ return mc_probe(dev, MC13XXX_MODE_SPI);
+}
+
static struct driver_d mc_spi_driver = {
.name = "mc13xxx-spi",
.probe = mc_spi_probe,
+ .of_compatible = DRV_OF_COMPAT(mc13892_dt_ids),
};
-static int mc_init(void)
+static int mc_spi_init(void)
{
- register_driver(&mc_i2c_driver);
- register_driver(&mc_spi_driver);
- return 0;
+ return spi_register_driver(&mc_spi_driver);
}
-device_initcall(mc_init);
+device_initcall(mc_spi_init);
+#endif
diff --git a/drivers/mfd/mc34704.c b/drivers/mfd/mc34704.c
index 6dc04c7330..276b723b1b 100644
--- a/drivers/mfd/mc34704.c
+++ b/drivers/mfd/mc34704.c
@@ -130,7 +130,7 @@ static struct driver_d mc34704_driver = {
static int mc34704_init(void)
{
- register_driver(&mc34704_driver);
- return 0;
+ i2c_register_driver(&mc34704_driver);
+ return 0;
}
device_initcall(mc34704_init);
diff --git a/drivers/mfd/mc34708.c b/drivers/mfd/mc34708.c
index a3b3530082..b1166de6b8 100644
--- a/drivers/mfd/mc34708.c
+++ b/drivers/mfd/mc34708.c
@@ -262,31 +262,40 @@ static int mc_probe(struct device_d *dev, enum mc34708_mode mode)
return 0;
}
+#ifdef CONFIG_I2C
static int mc_i2c_probe(struct device_d *dev)
{
return mc_probe(dev, MC34708_MODE_I2C);
}
-static int mc_spi_probe(struct device_d *dev)
-{
- return mc_probe(dev, MC34708_MODE_SPI);
-}
-
static struct driver_d mc_i2c_driver = {
.name = "mc34708-i2c",
.probe = mc_i2c_probe,
};
+static int mc_i2c_init(void)
+{
+ return i2c_register_driver(&mc_i2c_driver);
+}
+
+device_initcall(mc_i2c_init);
+#endif
+
+#ifdef CONFIG_SPI
+static int mc_spi_probe(struct device_d *dev)
+{
+ return mc_probe(dev, MC34708_MODE_SPI);
+}
+
static struct driver_d mc_spi_driver = {
.name = "mc34708-spi",
.probe = mc_spi_probe,
};
-static int mc_init(void)
+static int mc_spi_init(void)
{
- register_driver(&mc_i2c_driver);
- register_driver(&mc_spi_driver);
- return 0;
+ return spi_register_driver(&mc_spi_driver);
}
-device_initcall(mc_init);
+device_initcall(mc_spi_init);
+#endif
diff --git a/drivers/mfd/mc9sdz60.c b/drivers/mfd/mc9sdz60.c
index 00ba0ffa87..76c62e331e 100644
--- a/drivers/mfd/mc9sdz60.c
+++ b/drivers/mfd/mc9sdz60.c
@@ -142,7 +142,7 @@ static struct driver_d mc_driver = {
static int mc_init(void)
{
- register_driver(&mc_driver);
+ i2c_register_driver(&mc_driver);
return 0;
}
diff --git a/drivers/mfd/stmpe-i2c.c b/drivers/mfd/stmpe-i2c.c
index 4af8b7b88c..12e95c16b4 100644
--- a/drivers/mfd/stmpe-i2c.c
+++ b/drivers/mfd/stmpe-i2c.c
@@ -146,7 +146,7 @@ static struct driver_d stmpe_driver = {
static int stmpe_init(void)
{
- register_driver(&stmpe_driver);
+ i2c_register_driver(&stmpe_driver);
return 0;
}
diff --git a/drivers/mfd/twl4030.c b/drivers/mfd/twl4030.c
index 191c91f36a..93097659c6 100644
--- a/drivers/mfd/twl4030.c
+++ b/drivers/mfd/twl4030.c
@@ -53,7 +53,7 @@ static struct driver_d twl_driver = {
static int twl_init(void)
{
- register_driver(&twl_driver);
+ i2c_register_driver(&twl_driver);
return 0;
}
diff --git a/drivers/mfd/twl6030.c b/drivers/mfd/twl6030.c
index 7ecfed8062..01728fd317 100644
--- a/drivers/mfd/twl6030.c
+++ b/drivers/mfd/twl6030.c
@@ -49,7 +49,7 @@ static struct driver_d twl_driver = {
static int twl_init(void)
{
- register_driver(&twl_driver);
+ i2c_register_driver(&twl_driver);
return 0;
}
diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c
index d28ae0744e..f541802a84 100644
--- a/drivers/mtd/mtdraw.c
+++ b/drivers/mtd/mtdraw.c
@@ -128,7 +128,8 @@ static ssize_t mtdraw_read(struct cdev *cdev, void *buf, size_t count,
skip = offset % (mtd->writesize + mtd->oobsize);
while (ret > 0 && count > 0) {
- toread = min_t(int, count, mtd->writesize + mtd->oobsize);
+ toread = min_t(int, count,
+ mtd->writesize + mtd->oobsize - skip);
ret = mtdraw_read_unaligned(mtd, buf, toread,
skip, numpage++ * mtd->writesize);
buf += ret;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 37e57b32ce..fe9a6e7ab3 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1137,7 +1137,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
{
struct nand_flash_dev *type = NULL;
int i, dev_id, maf_idx;
- int tmp_id, tmp_manf;
+ int id_data[8];
int ret;
/* Select the device */
@@ -1166,13 +1166,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
/* Read manufacturer and device IDs */
- tmp_manf = chip->read_byte(mtd);
- tmp_id = chip->read_byte(mtd);
+ id_data[0] = chip->read_byte(mtd);
+ id_data[1] = chip->read_byte(mtd);
- if (tmp_manf != *maf_id || tmp_id != dev_id) {
+ if (id_data[0] != *maf_id || id_data[1] != dev_id) {
printk(KERN_ERR "%s: second ID read did not match "
"%02x,%02x against %02x,%02x\n", __func__,
- *maf_id, dev_id, tmp_manf, tmp_id);
+ *maf_id, dev_id, id_data[0], id_data[1]);
return ERR_PTR(-ENODEV);
}
@@ -1196,29 +1196,75 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
}
}
+ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
+
+ /* Read entire ID string */
+
+ for (i = 0; i < 8; i++)
+ id_data[i] = chip->read_byte(mtd);
+
if (!mtd->name)
mtd->name = type->name;
chip->chipsize = type->chipsize << 20;
- /* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
int extid;
/* The 3rd id byte holds MLC / multichip data */
- chip->cellinfo = chip->read_byte(mtd);
+ chip->cellinfo = id_data[2];
/* The 4th id byte is the important one */
- extid = chip->read_byte(mtd);
- /* Calc pagesize */
- mtd->writesize = 1024 << (extid & 0x3);
- extid >>= 2;
- /* Calc oobsize */
- mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9);
- extid >>= 2;
- /* Calc blocksize. Blocksize is multiples of 64KiB */
- mtd->erasesize = (64 * 1024) << (extid & 0x03);
- extid >>= 2;
- /* Get buswidth information */
- busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ extid = id_data[3];
+
+ /*
+ * Field definitions are in the following datasheets:
+ * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32)
+ * New style (6 byte ID): Samsung K9GBG08U0M (p.40)
+ *
+ * Check for wraparound + Samsung ID + nonzero 6th byte
+ * to decide what to do.
+ */
+ if (id_data[0] == id_data[6] && id_data[1] == id_data[7] &&
+ id_data[0] == NAND_MFR_SAMSUNG &&
+ (chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+ id_data[5] != 0x00) {
+ /* Calc pagesize */
+ mtd->writesize = 2048 << (extid & 0x03);
+ extid >>= 2;
+ /* Calc oobsize */
+ switch (extid & 0x03) {
+ case 1:
+ mtd->oobsize = 128;
+ break;
+ case 2:
+ mtd->oobsize = 218;
+ break;
+ case 3:
+ mtd->oobsize = 400;
+ break;
+ default:
+ mtd->oobsize = 436;
+ break;
+ }
+ extid >>= 2;
+ /* Calc blocksize */
+ mtd->erasesize = (128 * 1024) <<
+ (((extid >> 1) & 0x04) | (extid & 0x03));
+ busw = 0;
+ } else {
+ /* Calc pagesize */
+ mtd->writesize = 1024 << (extid & 0x03);
+ extid >>= 2;
+ /* Calc oobsize */
+ mtd->oobsize = (8 << (extid & 0x01)) *
+ (mtd->writesize >> 9);
+ extid >>= 2;
+ /* Calc blocksize. Blocksize is multiples of 64KiB */
+ mtd->erasesize = (64 * 1024) << (extid & 0x03);
+ extid >>= 2;
+ /* Get buswidth information */
+ busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+ }
+
} else {
/*
@@ -1228,6 +1274,19 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
mtd->writesize = type->pagesize;
mtd->oobsize = mtd->writesize / 32;
busw = type->options & NAND_BUSWIDTH_16;
+
+ /*
+ * Check for Spansion/AMD ID + repeating 5th, 6th byte since
+ * some Spansion chips have erasesize that conflicts with size
+ * listed in nand_ids table
+ * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39)
+ */
+ if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 &&
+ id_data[5] == 0x00 && id_data[6] == 0x00 &&
+ id_data[7] == 0x00 && mtd->writesize == 512) {
+ mtd->erasesize = 128 * 1024;
+ mtd->erasesize <<= ((id_data[3] & 0x03) << 1);
+ }
}
/* Try to identify manufacturer */
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index cb53fc61ca..72593d44a8 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -118,6 +118,36 @@ struct nand_flash_dev nand_flash_ids[] = {
{__NANDSTR("NAND 2GiB 1,8V 16-bit"), 0xB5, 0, 2048, 0, LP_OPTIONS16},
{__NANDSTR("NAND 2GiB 3,3V 16-bit"), 0xC5, 0, 2048, 0, LP_OPTIONS16},
+ /* 32 Gigabit */
+ {__NANDSTR("NAND 4GiB 1,8V 8-bit"), 0xA7, 0, 4096, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 4GiB 3,3V 8-bit"), 0xD7, 0, 4096, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 4GiB 1,8V 16-bit"), 0xB7, 0, 4096, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 4GiB 3,3V 16-bit"), 0xC7, 0, 4096, 0, LP_OPTIONS16},
+
+ /* 64 Gigabit */
+ {__NANDSTR("NAND 8GiB 1,8V 8-bit"), 0xAE, 0, 8192, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 8GiB 3,3V 8-bit"), 0xDE, 0, 8192, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 8GiB 1,8V 16-bit"), 0xBE, 0, 8192, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 8GiB 3,3V 16-bit"), 0xCE, 0, 8192, 0, LP_OPTIONS16},
+
+ /* 128 Gigabit */
+ {__NANDSTR("NAND 16GiB 1,8V 8-bit"), 0x1A, 0, 16384, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 16GiB 3,3V 8-bit"), 0x3A, 0, 16384, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 16GiB 1,8V 16-bit"), 0x2A, 0, 16384, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 16GiB 3,3V 16-bit"), 0x4A, 0, 16384, 0, LP_OPTIONS16},
+
+ /* 256 Gigabit */
+ {__NANDSTR("NAND 32GiB 1,8V 8-bit"), 0x1C, 0, 32768, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 32GiB 3,3V 8-bit"), 0x3C, 0, 32768, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 32GiB 1,8V 16-bit"), 0x2C, 0, 32768, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 32GiB 3,3V 16-bit"), 0x4C, 0, 32768, 0, LP_OPTIONS16},
+
+ /* 512 Gigabit */
+ {__NANDSTR("NAND 64GiB 1,8V 8-bit"), 0x1E, 0, 65536, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 64GiB 3,3V 8-bit"), 0x3E, 0, 65536, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 64GiB 1,8V 16-bit"), 0x2E, 0, 65536, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 64GiB 3,3V 16-bit"), 0x4E, 0, 65536, 0, LP_OPTIONS16},
+
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
* have a strange page/block layout ! The chosen minimum erasesize is
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 3c5f729db3..b3e5a83dc1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -19,64 +19,71 @@ config HAS_DESIGNWARE_ETH
config ARCH_HAS_FEC_IMX
bool
-config MIIDEV
+config PHYLIB
bool
menu "Network drivers "
depends on NET
+source "drivers/net/phy/Kconfig"
+
config DRIVER_NET_CS8900
bool "cs8900 ethernet driver"
depends on HAS_CS8900
config DRIVER_NET_SMC911X
bool "smc911x ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the SMSC LAN9[12]1[567]
ethernet chip.
config DRIVER_NET_SMC91111
bool "smc91111 ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the SMSC LAN91C111
ethernet chip.
+config DRIVER_NET_DAVINCI_EMAC
+ bool "TI Davinci/OMAP EMAC ethernet driver"
+ depends on ARCH_DAVINCI || ARCH_OMAP3
+ select PHYLIB
+
config DRIVER_NET_DM9K
bool "Davicom dm9k[E|A|B] ethernet driver"
depends on HAS_DM9000
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_NETX
bool "Hilscher Netx ethernet driver"
depends on HAS_NETX_ETHER
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_AT91_ETHER
bool "at91 ethernet driver"
depends on HAS_AT91_ETHER
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_MPC5200
bool "MPC5200 Ethernet driver"
depends on ARCH_MPC5200
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_FEC_IMX
bool "i.MX FEC Ethernet driver"
depends on ARCH_HAS_FEC_IMX
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_EP93XX
bool "EP93xx Ethernet driver"
depends on ARCH_EP93XX
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_MACB
bool "macb Ethernet driver"
depends on HAS_MACB
- select MIIDEV
+ select PHYLIB
config DRIVER_NET_TAP
bool "tap Ethernet driver"
@@ -85,7 +92,7 @@ config DRIVER_NET_TAP
config DRIVER_NET_TSE
depends on NIOS2
bool "Altera TSE ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the Altera TSE MAC.
@@ -100,14 +107,14 @@ config TSE_USE_DEDICATED_DESC_MEM
config DRIVER_NET_KS8851_MLL
bool "ks8851 mll ethernet driver"
- select MIIDEV
+ select PHYLIB
help
This option enables support for the Micrel KS8851 MLL
ethernet chip.
config DRIVER_NET_DESIGNWARE
bool "Designware Universal MAC ethernet driver"
- select MIIDEV
+ select PHYLIB
depends on HAS_DESIGNWARE_ETH
help
This option enables support for the Synopsys
@@ -121,9 +128,16 @@ config DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR
config DRIVER_NET_GIANFAR
bool "Gianfar Ethernet"
depends on ARCH_MPC85XX
- select MIIDEV
+ select PHYLIB
source "drivers/net/usb/Kconfig"
+config DRIVER_NET_MICREL
+ depends on SPI
+ bool "Micrel KSZ8864RMN Ethernet Switch driver"
+ help
+ This option enables support for enabling the Micrel
+ KSZ8864RMN Ethernet Switch over SPI.
+
endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 4d960e856f..4e6b49b191 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o
obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o
obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
+obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o
obj-$(CONFIG_DRIVER_NET_DM9K) += dm9k.o
obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o
obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o
@@ -9,9 +10,10 @@ obj-$(CONFIG_DRIVER_NET_FEC_IMX) += fec_imx.o
obj-$(CONFIG_DRIVER_NET_EP93XX) += ep93xx.o
obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
-obj-$(CONFIG_MIIDEV) += miidev.o
+obj-$(CONFIG_PHYLIB) += phy/
obj-$(CONFIG_NET_USB) += usb/
obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
obj-$(CONFIG_DRIVER_NET_KS8851_MLL) += ks8851_mll.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
obj-$(CONFIG_DRIVER_NET_GIANFAR) += gianfar.o
+obj-$(CONFIG_DRIVER_NET_MICREL) += ksz8864rmn.o
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c
index 4643f001b4..9323f38019 100644
--- a/drivers/net/altera_tse.c
+++ b/drivers/net/altera_tse.c
@@ -22,10 +22,10 @@
#include <common.h>
#include <net.h>
-#include <miidev.h>
#include <init.h>
#include <clock.h>
#include <linux/mii.h>
+#include <linux/phy.h>
#include <io.h>
#include <asm/dma-mapping.h>
@@ -243,10 +243,9 @@ static int tse_set_ethaddr(struct eth_device *edev, unsigned char *m)
return 0;
}
-static int tse_phy_read(struct mii_device *mdev, int phy_addr, int reg)
+static int tse_phy_read(struct mii_bus *bus, int phy_addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct altera_tse_priv *priv = edev->priv;
+ struct altera_tse_priv *priv = bus->priv;
struct alt_tse_mac *mac_dev = priv->tse_regs;
uint32_t *mdio_regs;
@@ -257,10 +256,9 @@ static int tse_phy_read(struct mii_device *mdev, int phy_addr, int reg)
return readl(&mdio_regs[reg]) & 0xFFFF;
}
-static int tse_phy_write(struct mii_device *mdev, int phy_addr, int reg, int val)
+static int tse_phy_write(struct mii_bus *bus, int phy_addr, int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
- struct altera_tse_priv *priv = edev->priv;
+ struct altera_tse_priv *priv = bus->priv;
struct alt_tse_mac *mac_dev = priv->tse_regs;
uint32_t *mdio_regs;
@@ -343,9 +341,12 @@ static void tse_reset(struct eth_device *edev)
static int tse_eth_open(struct eth_device *edev)
{
struct altera_tse_priv *priv = edev->priv;
+ int ret;
- miidev_wait_aneg(priv->miidev);
- miidev_print_status(priv->miidev);
+ ret = phy_device_connect(edev, priv->miibus, priv->phy_addr, NULL, 0,
+ PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
return 0;
}
@@ -484,15 +485,13 @@ static int tse_init_dev(struct eth_device *edev)
/* enable MAC */
writel(ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK, &mac_dev->command_config);
- miidev_restart_aneg(priv->miidev);
-
return 0;
}
static int tse_probe(struct device_d *dev)
{
struct altera_tse_priv *priv;
- struct mii_device *miidev;
+ struct mii_bus *miibus;
struct eth_device *edev;
struct alt_sgdma_descriptor *rx_desc;
struct alt_sgdma_descriptor *tx_desc;
@@ -501,7 +500,7 @@ static int tse_probe(struct device_d *dev)
#endif
edev = xzalloc(sizeof(struct eth_device));
priv = xzalloc(sizeof(struct altera_tse_priv));
- miidev = xzalloc(sizeof(struct mii_device));
+ miibus = xzalloc(sizeof(struct mii_bus));
edev->priv = priv;
@@ -523,7 +522,7 @@ static int tse_probe(struct device_d *dev)
if (!tx_desc) {
free(edev);
- free(miidev);
+ free(miibus);
return 0;
}
#endif
@@ -537,22 +536,19 @@ static int tse_probe(struct device_d *dev)
priv->rx_desc = rx_desc;
priv->tx_desc = tx_desc;
- priv->miidev = miidev;
+ priv->miibus = miibus;
- miidev->read = tse_phy_read;
- miidev->write = tse_phy_write;
- miidev->flags = 0;
- miidev->edev = edev;
- miidev->parent = dev;
+ miibus->read = tse_phy_read;
+ miibus->write = tse_phy_write;
+ miibus->priv = priv;
+ miibus->parent = dev;
if (dev->platform_data != NULL)
- miidev->address = *((int8_t *)(dev->platform_data));
- else {
- printf("No PHY address specified.\n");
- return -ENODEV;
- }
+ priv->phy_addr = *((int8_t *)(dev->platform_data));
+ else
+ priv->phy_addr = -1;
- mii_register(miidev);
+ mdiobus_register(miibus);
return eth_register(edev);
}
diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h
index 866dbce8c3..5a66a7d289 100644
--- a/drivers/net/altera_tse.h
+++ b/drivers/net/altera_tse.h
@@ -292,7 +292,8 @@ struct altera_tse_priv {
void __iomem *sgdma_tx_regs;
void __iomem *rx_desc;
void __iomem *tx_desc;
- struct mii_device *miidev;
+ int phy_addr;
+ struct mii_bus *miibus;
};
#endif /* _ALTERA_TSE_H_ */
diff --git a/drivers/net/at91_ether.c b/drivers/net/at91_ether.c
index cd00dabf4a..dee2039b11 100644
--- a/drivers/net/at91_ether.c
+++ b/drivers/net/at91_ether.c
@@ -26,7 +26,6 @@
#include <driver.h>
#include <xfuncs.h>
#include <init.h>
-#include <miidev.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/at91rm9200_emac.h>
@@ -36,18 +35,18 @@
#include <linux/mii.h>
#include <errno.h>
#include <asm/mmu.h>
+#include <linux/phy.h>
#include "at91_ether.h"
-#define SPEED_100 1
-#define DUPLEX_FULL 1
-
struct ether_device {
struct eth_device netdev;
- struct mii_device miidev;
+ struct mii_bus miibus;
struct rbf_t *rbfp;
struct rbf_t *rbfdt;
unsigned char *rbf_framebuf;
+ int phy_addr;
+ phy_interface_t interface;
};
#define to_ether(_nd) container_of(_nd, struct ether_device, netdev)
@@ -94,7 +93,7 @@ static inline int at91_phy_wait(void)
return 0;
}
-static int at91_ether_mii_read(struct mii_device *dev, int addr, int reg)
+static int at91_ether_mii_read(struct mii_bus *dev, int addr, int reg)
{
int value;
@@ -116,7 +115,7 @@ out:
return value;
}
-static int at91_ether_mii_write(struct mii_device *dev, int addr, int reg, int val)
+static int at91_ether_mii_write(struct mii_bus *dev, int addr, int reg, u16 val)
{
int ret;
@@ -132,19 +131,19 @@ static int at91_ether_mii_write(struct mii_device *dev, int addr, int reg, int v
return ret;
}
-static void update_linkspeed(struct mii_device *dev, int speed, int duplex)
+static void update_linkspeed(struct eth_device *edev)
{
unsigned int mac_cfg;
/* Update the MAC */
mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD);
- if (speed == SPEED_100) {
- if (duplex == DUPLEX_FULL) /* 100 Full Duplex */
+ if (edev->phydev->speed == SPEED_100) {
+ if (edev->phydev->duplex)
mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD;
else /* 100 Half Duplex */
mac_cfg |= AT91_EMAC_SPD;
} else {
- if (duplex == DUPLEX_FULL) /* 10 Full Duplex */
+ if (edev->phydev->duplex)
mac_cfg |= AT91_EMAC_FD;
else {} /* 10 Half Duplex */
}
@@ -157,11 +156,12 @@ static int at91_ether_open(struct eth_device *edev)
unsigned long ctl;
struct ether_device *etdev = to_ether(edev);
unsigned char *rbf_framebuf = etdev->rbf_framebuf;
+ int ret;
- miidev_wait_aneg(&etdev->miidev);
- miidev_print_status(&etdev->miidev);
-
- update_linkspeed(&etdev->miidev, SPEED_100, DUPLEX_FULL);
+ ret = phy_device_connect(edev, &etdev->miibus, etdev->phy_addr,
+ update_linkspeed, 0, etdev->interface);
+ if (ret)
+ return ret;
/* Clear internal statistics */
ctl = at91_emac_read(AT91_EMAC_CTL);
@@ -295,7 +295,7 @@ static int at91_ether_probe(struct device_d *dev)
unsigned int mac_cfg;
struct ether_device *ether_dev;
struct eth_device *edev;
- struct mii_device *miidev;
+ struct mii_bus *miibus;
unsigned long ether_hz;
struct clk *pclk;
struct at91_ether_platform_data *pdata;
@@ -310,7 +310,7 @@ static int at91_ether_probe(struct device_d *dev)
ether_dev = xzalloc(sizeof(struct ether_device));
edev = &ether_dev->netdev;
- miidev = &ether_dev->miidev;
+ miibus = &ether_dev->miibus;
edev->priv = ether_dev;
edev->init = at91_ether_init;
@@ -323,10 +323,9 @@ static int at91_ether_probe(struct device_d *dev)
ether_dev->rbf_framebuf = dma_alloc_coherent(MAX_RX_DESCR * MAX_RBUFF_SZ);
ether_dev->rbfdt = dma_alloc_coherent(sizeof(struct rbf_t) * MAX_RX_DESCR);
- miidev->address = pdata->phy_addr;
- miidev->read = at91_ether_mii_read;
- miidev->write = at91_ether_mii_write;
- miidev->edev = edev;
+ ether_dev->phy_addr = pdata->phy_addr;
+ miibus->read = at91_ether_mii_read;
+ miibus->write = at91_ether_mii_write;
/* Sanitize the clocks */
mac_cfg = at91_emac_read(AT91_EMAC_CFG);
@@ -343,12 +342,16 @@ static int at91_ether_probe(struct device_d *dev)
mac_cfg |= AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG;
- if (pdata->flags & AT91SAM_ETHER_RMII)
+ if (pdata->flags & AT91SAM_ETHER_RMII) {
+ ether_dev->interface = PHY_INTERFACE_MODE_RGMII;
mac_cfg |= AT91_EMAC_RMII;
+ } else {
+ ether_dev->interface = PHY_INTERFACE_MODE_MII;
+ }
at91_emac_write(AT91_EMAC_CFG, mac_cfg);
- mii_register(miidev);
+ mdiobus_register(miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
new file mode 100644
index 0000000000..7d4dbdcdd9
--- /dev/null
+++ b/drivers/net/davinci_emac.c
@@ -0,0 +1,618 @@
+/*
+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
+ *
+ * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
+ * follows:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.c
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+
+ * Modifications:
+ * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
+ * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
+ *
+ */
+
+#include <common.h>
+#include <io.h>
+#include <clock.h>
+#include <net.h>
+#include <malloc.h>
+#include <init.h>
+#include <asm/mmu.h>
+#include <asm/system.h>
+#include <linux/phy.h>
+#include <mach/emac_defs.h>
+#include <net/davinci_emac.h>
+#include "davinci_emac.h"
+
+struct davinci_emac_priv {
+ struct device_d *dev;
+ struct eth_device edev;
+ struct mii_bus miibus;
+
+ /* EMAC Addresses */
+ void __iomem *adap_emac; /* = EMAC_BASE_ADDR */
+ void __iomem *adap_ewrap; /* = EMAC_WRAPPER_BASE_ADDR */
+ void __iomem *adap_mdio; /* = EMAC_MDIO_BASE_ADDR */
+
+ /* EMAC descriptors */
+ void __iomem *emac_desc_base; /* = EMAC_WRAPPER_RAM_ADDR */
+ void __iomem *emac_rx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE */
+ void __iomem *emac_tx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE */
+ void __iomem *emac_rx_active_head; /* = 0 */
+ void __iomem *emac_rx_active_tail; /* = 0 */
+ int emac_rx_queue_active; /* = 0 */
+
+ /* Receive packet buffers */
+ unsigned char *emac_rx_buffers; /* [EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)] */
+
+ /* PHY-specific information */
+ phy_interface_t interface;
+ uint8_t phy_addr;
+ uint32_t phy_flags;
+
+ /* mac_addr[0] goes out on the wire first */
+ uint8_t mac_addr[6];
+};
+
+#ifdef EMAC_HW_RAM_ADDR
+static inline uint32_t BD_TO_HW(void __iomem *x)
+{
+ if (x == 0)
+ return 0;
+
+ return (uint32_t)(x) - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
+}
+
+static inline void __iomem *HW_TO_BD(uint32_t x)
+{
+ if (x == 0)
+ return 0;
+
+ return (struct emac_desc*)(x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR);
+}
+#else
+#define BD_TO_HW(x) (x)
+#define HW_TO_BD(x) (x)
+#endif
+
+static void davinci_eth_mdio_enable(struct davinci_emac_priv *priv)
+{
+ uint32_t clkdiv;
+
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+
+ dev_dbg(priv->dev, "mdio_enable + 0x%08x\n",
+ readl(priv->adap_mdio + EMAC_MDIO_CONTROL));
+ writel((clkdiv & 0xff) |
+ MDIO_CONTROL_ENABLE |
+ MDIO_CONTROL_FAULT |
+ MDIO_CONTROL_FAULT_ENABLE,
+ priv->adap_mdio + EMAC_MDIO_CONTROL);
+ dev_dbg(priv->dev, "mdio_enable - 0x%08x\n",
+ readl(priv->adap_mdio + EMAC_MDIO_CONTROL));
+
+ while (readl(priv->adap_mdio + EMAC_MDIO_CONTROL) & MDIO_CONTROL_IDLE);
+}
+
+static int davinci_miibus_read(struct mii_bus *bus, int addr, int reg)
+{
+ struct davinci_emac_priv *priv = bus->priv;
+ uint16_t value;
+ int tmp;
+
+ while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_READ |
+ ((reg & 0x1f) << 21) |
+ ((addr & 0x1f) << 16),
+ priv->adap_mdio + EMAC_MDIO_USERACCESS0);
+
+ /* Wait for command to complete */
+ while ((tmp = readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0)) & MDIO_USERACCESS0_GO);
+
+ if (tmp & MDIO_USERACCESS0_ACK) {
+ value = tmp & 0xffff;
+ dev_dbg(priv->dev, "davinci_miibus_read: addr=0x%02x reg=0x%02x value=0x%04x\n",
+ addr, reg, value);
+ return value;
+ }
+
+ return -1;
+}
+
+static int davinci_miibus_write(struct mii_bus *bus, int addr, int reg, u16 value)
+{
+ struct davinci_emac_priv *priv = bus->priv;
+ while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ dev_dbg(priv->dev, "davinci_miibus_write: addr=0x%02x reg=0x%02x value=0x%04x\n",
+ addr, reg, value);
+ writel(MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_WRITE |
+ ((reg & 0x1f) << 21) |
+ ((addr & 0x1f) << 16) |
+ (value & 0xffff),
+ priv->adap_mdio + EMAC_MDIO_USERACCESS0);
+
+ /* Wait for command to complete */
+ while (readl(priv->adap_mdio + EMAC_MDIO_USERACCESS0) & MDIO_USERACCESS0_GO);
+
+ return 0;
+}
+
+static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+ return -1;
+}
+
+/*
+ * This function must be called before emac_open() if you want to override
+ * the default mac address.
+ */
+static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *addr)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ int i;
+
+ for (i = 0; i < sizeof(priv->mac_addr); i++)
+ priv->mac_addr[i] = addr[i];
+ return 0;
+}
+
+static int davinci_emac_init(struct eth_device *edev)
+{
+ dev_dbg(&edev->dev, "* emac_init\n");
+ return 0;
+}
+
+static int davinci_emac_open(struct eth_device *edev)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ uint32_t clkdiv, cnt;
+ void __iomem *rx_desc;
+ unsigned long mac_hi, mac_lo;
+ int ret;
+
+ dev_dbg(priv->dev, "+ emac_open\n");
+
+ dev_dbg(priv->dev, "emac->TXIDVER: 0x%08x\n",
+ readl(priv->adap_emac + EMAC_TXIDVER));
+ dev_dbg(priv->dev, "emac->RXIDVER: 0x%08x\n",
+ readl(priv->adap_emac + EMAC_RXIDVER));
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ writel(1, priv->adap_emac + EMAC_SOFTRESET);
+ while (readl(priv->adap_emac + EMAC_SOFTRESET) != 0);
+ writel(1, priv->adap_ewrap + EMAC_EWRAP_SOFTRESET);
+ while (readl(priv->adap_ewrap + EMAC_EWRAP_SOFTRESET) != 0);
+
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2MISCEN);
+
+ rx_desc = priv->emac_rx_desc;
+
+ /*
+ * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
+ * receive)
+ * Use channel 0 only - other channels are disabled
+ */
+ writel(0, priv->adap_emac + EMAC_MACINDEX);
+ mac_hi = (priv->mac_addr[3] << 24) |
+ (priv->mac_addr[2] << 16) |
+ (priv->mac_addr[1] << 8) |
+ (priv->mac_addr[0]);
+ mac_lo = (priv->mac_addr[5] << 8) |
+ (priv->mac_addr[4]);
+
+ writel(mac_hi, priv->adap_emac + EMAC_MACADDRHI);
+ writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
+ priv->adap_emac + EMAC_MACADDRLO);
+
+ /* Set source MAC address - REQUIRED */
+ writel(mac_hi, priv->adap_emac + EMAC_MACSRCADDRHI);
+ writel(mac_lo, priv->adap_emac + EMAC_MACSRCADDRLO);
+
+ /* Set DMA head and completion pointers to 0 */
+ for(cnt = 0; cnt < 8; cnt++) {
+ writel(0, (void *)priv->adap_emac + EMAC_TX0HDP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_RX0HDP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_TX0CP + 4 * cnt);
+ writel(0, (void *)priv->adap_emac + EMAC_RX0CP + 4 * cnt);
+ }
+
+ /* Clear Statistics (do this before setting MacControl register) */
+ for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
+ writel(0, (void *)priv->adap_emac + EMAC_RXGOODFRAMES + 4 * cnt);
+
+ /* No multicast addressing */
+ writel(0, priv->adap_emac + EMAC_MACHASH1);
+ writel(0, priv->adap_emac + EMAC_MACHASH2);
+
+ writel(0x01, priv->adap_emac + EMAC_TXCONTROL);
+ writel(0x01, priv->adap_emac + EMAC_RXCONTROL);
+
+ /* Create RX queue and set receive process in place */
+ priv->emac_rx_active_head = priv->emac_rx_desc;
+ for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
+ writel(BD_TO_HW(rx_desc + EMAC_DESC_SIZE), rx_desc + EMAC_DESC_NEXT);
+ writel(&priv->emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)], rx_desc + EMAC_DESC_BUFFER);
+ writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_desc + EMAC_DESC_BUFF_OFF_LEN);
+ writel(EMAC_CPPI_OWNERSHIP_BIT, rx_desc + EMAC_DESC_PKT_FLAG_LEN);
+ rx_desc += EMAC_DESC_SIZE;
+ }
+
+ /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
+ rx_desc -= EMAC_DESC_SIZE;
+ writel(0, rx_desc + EMAC_DESC_NEXT);
+ priv->emac_rx_active_tail = rx_desc;
+ priv->emac_rx_queue_active = 1;
+
+ /* Enable TX/RX */
+ writel(EMAC_MAX_ETHERNET_PKT_SIZE, priv->adap_emac + EMAC_RXMAXLEN);
+ writel(0, priv->adap_emac + EMAC_RXBUFFEROFFSET);
+
+ /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
+ writel(EMAC_RXMBPENABLE_RXBROADEN, priv->adap_emac + EMAC_RXMBPENABLE);
+
+ /* Enable ch 0 only */
+ writel(0x01, priv->adap_emac + EMAC_RXUNICASTSET);
+
+ /* Enable MII interface and full duplex mode (using RMMI) */
+ writel((EMAC_MACCONTROL_MIIEN_ENABLE |
+ EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
+ EMAC_MACCONTROL_RMIISPEED_100),
+ priv->adap_emac + EMAC_MACCONTROL);
+
+ /* Init MDIO & get link state */
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+ writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
+ priv->adap_mdio + EMAC_MDIO_CONTROL);
+
+ /* Start receive process */
+ writel(BD_TO_HW(priv->emac_rx_desc), priv->adap_emac + EMAC_RX0HDP);
+
+ ret = phy_device_connect(edev, &priv->miibus, priv->phy_addr, NULL,
+ priv->phy_flags, priv->interface);
+ if (ret)
+ return ret;
+
+ dev_dbg(priv->dev, "- emac_open\n");
+
+ return 0;
+}
+
+/* EMAC Channel Teardown */
+static void davinci_eth_ch_teardown(struct davinci_emac_priv *priv, int ch)
+{
+ uint32_t dly = 0xff;
+ uint32_t cnt;
+
+ dev_dbg(priv->dev, "+ emac_ch_teardown\n");
+
+ if (ch == EMAC_CH_TX) {
+ /* Init TX channel teardown */
+ writel(0, priv->adap_emac + EMAC_TXTEARDOWN);
+ for(cnt = 0; cnt != 0xfffffffc; cnt = readl(priv->adap_emac + EMAC_TX0CP)) {
+ /* Wait here for Tx teardown completion interrupt to occur
+ * Note: A task delay can be called here to pend rather than
+ * occupying CPU cycles - anyway it has been found that teardown
+ * takes very few cpu cycles and does not affect functionality */
+ dly--;
+ udelay(1);
+ if (dly == 0)
+ break;
+ }
+ writel(cnt, priv->adap_emac + EMAC_TX0CP);
+ writel(0, priv->adap_emac + EMAC_TX0HDP);
+ } else {
+ /* Init RX channel teardown */
+ writel(0, priv->adap_emac + EMAC_RXTEARDOWN);
+ for(cnt = 0; cnt != 0xfffffffc; cnt = readl(priv->adap_emac + EMAC_RX0CP)) {
+ /* Wait here for Rx teardown completion interrupt to occur
+ * Note: A task delay can be called here to pend rather than
+ * occupying CPU cycles - anyway it has been found that teardown
+ * takes very few cpu cycles and does not affect functionality */
+ dly--;
+ udelay(1);
+ if (dly == 0)
+ break;
+ }
+ writel(cnt, priv->adap_emac + EMAC_RX0CP);
+ writel(0, priv->adap_emac + EMAC_RX0HDP);
+ }
+
+ dev_dbg(priv->dev, "- emac_ch_teardown\n");
+}
+
+static void davinci_emac_halt(struct eth_device *edev)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+
+ dev_dbg(priv->dev, "+ emac_halt\n");
+
+ davinci_eth_ch_teardown(priv, EMAC_CH_TX); /* TX Channel teardown */
+ davinci_eth_ch_teardown(priv, EMAC_CH_RX); /* RX Channel teardown */
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ writel(1, priv->adap_emac + EMAC_SOFTRESET);
+ writel(1, priv->adap_ewrap + EMAC_EWRAP_SOFTRESET);
+
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2RXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2TXEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C0MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C1MISCEN);
+ writel(0, priv->adap_ewrap + EMAC_EWRAP_C2MISCEN);
+
+ dev_dbg(priv->dev, "- emac_halt\n");
+}
+
+/*
+ * This function sends a single packet on the network and returns
+ * positive number (number of bytes transmitted) or negative for error
+ */
+static int davinci_emac_send(struct eth_device *edev, void *packet, int length)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ uint64_t start;
+ int ret_status;
+
+ dev_dbg(priv->dev, "+ emac_send (length %d)\n", length);
+
+ /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
+ if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
+ length = EMAC_MIN_ETHERNET_PKT_SIZE;
+ }
+
+ /* Populate the TX descriptor */
+ writel(0, priv->emac_tx_desc + EMAC_DESC_NEXT);
+ writel((uint8_t *) packet, priv->emac_tx_desc + EMAC_DESC_BUFFER);
+ writel((length & 0xffff), priv->emac_tx_desc + EMAC_DESC_BUFF_OFF_LEN);
+ writel(((length & 0xffff) | EMAC_CPPI_SOP_BIT |
+ EMAC_CPPI_OWNERSHIP_BIT |
+ EMAC_CPPI_EOP_BIT),
+ priv->emac_tx_desc + EMAC_DESC_PKT_FLAG_LEN);
+ dma_flush_range((ulong) packet, (ulong)packet + length);
+ /* Send the packet */
+ writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0HDP);
+
+ /* Wait for packet to complete or link down */
+ start = get_time_ns();
+ while (1) {
+ if (readl(priv->adap_emac + EMAC_TXINTSTATRAW) & 0x01) {
+ /* Acknowledge the TX descriptor */
+ writel(BD_TO_HW(priv->emac_tx_desc), priv->adap_emac + EMAC_TX0CP);
+ ret_status = 0;
+ break;
+ }
+ if (is_timeout(start, 100 * MSECOND)) {
+ ret_status = -ETIMEDOUT;
+ break;
+ }
+ }
+
+ dev_dbg(priv->dev, "- emac_send (ret_status %i)\n", ret_status);
+ return ret_status;
+}
+
+/*
+ * This function handles receipt of a packet from the network
+ */
+static int davinci_emac_recv(struct eth_device *edev)
+{
+ struct davinci_emac_priv *priv = edev->priv;
+ void __iomem *rx_curr_desc, *curr_desc, *tail_desc;
+ unsigned char *pkt;
+ int status, len, ret = -1;
+
+ dev_dbg(priv->dev, "+ emac_recv\n");
+
+ rx_curr_desc = priv->emac_rx_active_head;
+ status = readl(rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
+ if (status & EMAC_CPPI_OWNERSHIP_BIT) {
+ ret = 0;
+ goto out;
+ }
+
+ if (status & EMAC_CPPI_RX_ERROR_FRAME) {
+ /* Error in packet - discard it and requeue desc */
+ dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n");
+ } else {
+ pkt = (unsigned char *)readl(rx_curr_desc + EMAC_DESC_BUFFER);
+ len = readl(rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN) & 0xffff;
+ dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len);
+ dma_inv_range((ulong)pkt,
+ (ulong)readl(rx_curr_desc + EMAC_DESC_BUFFER) + len);
+ net_receive(pkt, len);
+ ret = len;
+ }
+
+ /* Ack received packet descriptor */
+ writel(BD_TO_HW(rx_curr_desc), priv->adap_emac + EMAC_RX0CP);
+ curr_desc = rx_curr_desc;
+ priv->emac_rx_active_head = HW_TO_BD(readl(rx_curr_desc + EMAC_DESC_NEXT));
+
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ if (priv->emac_rx_active_head) {
+ writel(BD_TO_HW(priv->emac_rx_active_head),
+ priv->adap_emac + EMAC_RX0HDP);
+ } else {
+ priv->emac_rx_queue_active = 0;
+ dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n");
+ }
+ }
+
+ /* Recycle RX descriptor */
+ writel(EMAC_MAX_ETHERNET_PKT_SIZE, rx_curr_desc + EMAC_DESC_BUFF_OFF_LEN);
+ writel(EMAC_CPPI_OWNERSHIP_BIT, rx_curr_desc + EMAC_DESC_PKT_FLAG_LEN);
+ writel(0, rx_curr_desc + EMAC_DESC_NEXT);
+
+ if (priv->emac_rx_active_head == 0) {
+ dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n");
+ priv->emac_rx_active_head = curr_desc;
+ priv->emac_rx_active_tail = curr_desc;
+ if (priv->emac_rx_queue_active != 0) {
+ writel(BD_TO_HW(priv->emac_rx_active_head), priv->adap_emac + EMAC_RX0HDP);
+ dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
+ priv->emac_rx_queue_active = 1;
+ }
+ } else {
+ tail_desc = priv->emac_rx_active_tail;
+ priv->emac_rx_active_tail = curr_desc;
+ writel(BD_TO_HW(curr_desc), tail_desc + EMAC_DESC_NEXT);
+ status = readl(tail_desc + EMAC_DESC_PKT_FLAG_LEN);
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ writel(BD_TO_HW(curr_desc), priv->adap_emac + EMAC_RX0HDP);
+ status &= ~EMAC_CPPI_EOQ_BIT;
+ writel(status, tail_desc + EMAC_DESC_PKT_FLAG_LEN);
+ }
+ }
+
+out:
+ dev_dbg(priv->dev, "- emac_recv\n");
+
+ return ret;
+}
+
+static int davinci_emac_probe(struct device_d *dev)
+{
+ struct davinci_emac_platform_data *pdata;
+ struct davinci_emac_priv *priv;
+ uint64_t start;
+ uint32_t phy_mask;
+
+ dev_dbg(dev, "+ emac_probe\n");
+
+ if (!dev->platform_data) {
+ dev_err(dev, "no platform_data\n");
+ return -ENODEV;
+ }
+ pdata = dev->platform_data;
+
+ priv = xzalloc(sizeof(*priv));
+ dev->priv = priv;
+
+ priv->dev = dev;
+
+ priv->adap_emac = dev_request_mem_region(dev, 0);
+ priv->adap_ewrap = dev_request_mem_region(dev, 1);
+ priv->adap_mdio = dev_request_mem_region(dev, 2);
+ priv->emac_desc_base = dev_request_mem_region(dev, 3);
+
+ /* EMAC descriptors */
+ priv->emac_rx_desc = priv->emac_desc_base + EMAC_RX_DESC_BASE;
+ priv->emac_tx_desc = priv->emac_desc_base + EMAC_TX_DESC_BASE;
+ priv->emac_rx_active_head = NULL;
+ priv->emac_rx_active_tail = NULL;
+ priv->emac_rx_queue_active = 0;
+
+ /* Receive packet buffers */
+ priv->emac_rx_buffers = xmemalign(4096, EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN));
+
+ priv->edev.priv = priv;
+ priv->edev.init = davinci_emac_init;
+ priv->edev.open = davinci_emac_open;
+ priv->edev.halt = davinci_emac_halt;
+ priv->edev.send = davinci_emac_send;
+ priv->edev.recv = davinci_emac_recv;
+ priv->edev.get_ethaddr = davinci_emac_get_ethaddr;
+ priv->edev.set_ethaddr = davinci_emac_set_ethaddr;
+ priv->edev.parent = dev;
+
+ davinci_eth_mdio_enable(priv);
+
+ start = get_time_ns();
+ while (1) {
+ phy_mask = readl(priv->adap_mdio + EMAC_MDIO_ALIVE);
+ if (phy_mask) {
+ dev_info(dev, "detected phy mask 0x%x\n", phy_mask);
+ phy_mask = ~phy_mask;
+ break;
+ }
+ if (is_timeout(start, 256 * MSECOND)) {
+ dev_err(dev, "no live phy, scanning all\n");
+ phy_mask = 0;
+ break;
+ }
+ }
+
+ if (pdata->interface_rmii)
+ priv->interface = PHY_INTERFACE_MODE_RMII;
+ else
+ priv->interface = PHY_INTERFACE_MODE_MII;
+ priv->phy_addr = pdata->phy_addr;
+ priv->phy_flags = pdata->force_link ? PHYLIB_FORCE_LINK : 0;
+
+ priv->miibus.read = davinci_miibus_read;
+ priv->miibus.write = davinci_miibus_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
+ priv->miibus.phy_mask = phy_mask;
+
+ mdiobus_register(&priv->miibus);
+
+ eth_register(&priv->edev);
+
+ dev_dbg(dev, "- emac_probe\n");
+ return 0;
+}
+
+static void davinci_emac_remove(struct device_d *dev)
+{
+ struct davinci_emac_priv *priv = dev->priv;
+
+ davinci_emac_halt(&priv->edev);
+}
+
+static struct driver_d davinci_emac_driver = {
+ .name = "davinci_emac",
+ .probe = davinci_emac_probe,
+ .remove = davinci_emac_remove,
+};
+
+static int davinci_emac_register(void)
+{
+ register_driver(&davinci_emac_driver);
+ return 0;
+}
+
+device_initcall(davinci_emac_register);
diff --git a/drivers/net/davinci_emac.h b/drivers/net/davinci_emac.h
new file mode 100644
index 0000000000..c5fa018fb3
--- /dev/null
+++ b/drivers/net/davinci_emac.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Based on:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.h
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------------
+ */
+
+#ifndef _DAVINCI_EMAC_H_
+#define _DAVINCI_EMAC_H_
+
+/* PHY mask - set only those phy number bits where phy is/can be connected */
+#define EMAC_MDIO_PHY_NUM 1
+#define EMAC_MDIO_PHY_MASK (1 << EMAC_MDIO_PHY_NUM)
+
+/* Ethernet Min/Max packet size */
+#define EMAC_MIN_ETHERNET_PKT_SIZE 60
+#define EMAC_MAX_ETHERNET_PKT_SIZE 1518
+#define EMAC_PKT_ALIGN 18 /* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */
+
+/* Number of RX packet buffers
+ * NOTE: Only 1 buffer supported as of now
+ */
+#define EMAC_MAX_RX_BUFFERS 10
+
+/***********************************************
+ ******** Internally used macros ***************
+ ***********************************************/
+
+#define EMAC_CH_TX 1
+#define EMAC_CH_RX 0
+
+/* Each descriptor occupies 4 words, lets start RX desc's at 0 and
+ * reserve space for 64 descriptors max
+ */
+#define EMAC_RX_DESC_BASE 0x0
+#define EMAC_TX_DESC_BASE 0x1000
+
+/* EMAC Teardown value */
+#define EMAC_TEARDOWN_VALUE 0xfffffffc
+
+/* MII Status Register */
+#define MII_STATUS_REG 1
+
+/* Number of statistics registers */
+#define EMAC_NUM_STATS 36
+
+/* EMAC Descriptor Offsets */
+#define EMAC_DESC_NEXT 0x0 /* Pointer to next descriptor in chain */
+#define EMAC_DESC_BUFFER 0x4 /* Pointer to data buffer */
+#define EMAC_DESC_BUFF_OFF_LEN 0x8 /* Buffer Offset(MSW) and Length(LSW) */
+#define EMAC_DESC_PKT_FLAG_LEN 0xc /* Packet Flags(MSW) and Length(LSW) */
+#define EMAC_DESC_SIZE 0x10
+
+/* CPPI bit positions */
+#define EMAC_CPPI_SOP_BIT (0x80000000)
+#define EMAC_CPPI_EOP_BIT (0x40000000)
+#define EMAC_CPPI_OWNERSHIP_BIT (0x20000000)
+#define EMAC_CPPI_EOQ_BIT (0x10000000)
+#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT (0x08000000)
+#define EMAC_CPPI_PASS_CRC_BIT (0x04000000)
+
+#define EMAC_CPPI_RX_ERROR_FRAME (0x03fc0000)
+
+#define EMAC_MACCONTROL_MIIEN_ENABLE (0x20)
+#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE (0x1)
+#define EMAC_MACCONTROL_GIGABIT_ENABLE (1 << 7)
+#define EMAC_MACCONTROL_GIGFORCE (1 << 17)
+#define EMAC_MACCONTROL_RMIISPEED_100 (1 << 15)
+
+#define EMAC_MAC_ADDR_MATCH (1 << 19)
+#define EMAC_MAC_ADDR_IS_VALID (1 << 20)
+
+#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE (0x200000)
+#define EMAC_RXMBPENABLE_RXBROADEN (0x2000)
+
+#define MDIO_CONTROL_IDLE (0x80000000)
+#define MDIO_CONTROL_ENABLE (0x40000000)
+#define MDIO_CONTROL_FAULT_ENABLE (0x40000)
+#define MDIO_CONTROL_FAULT (0x80000)
+#define MDIO_USERACCESS0_GO (0x80000000)
+#define MDIO_USERACCESS0_WRITE_READ (0x0)
+#define MDIO_USERACCESS0_WRITE_WRITE (0x40000000)
+#define MDIO_USERACCESS0_ACK (0x20000000)
+
+/* Ethernet MAC Registers */
+#define EMAC_TXIDVER 0x000
+#define EMAC_TXCONTROL 0x004
+#define EMAC_TXTEARDOWN 0x008
+#define EMAC_RXIDVER 0x010
+#define EMAC_RXCONTROL 0x014
+#define EMAC_RXTEARDOWN 0x018
+#define EMAC_TXINTSTATRAW 0x080
+#define EMAC_TXINTSTATMASKED 0x084
+#define EMAC_TXINTMASKSET 0x088
+#define EMAC_TXINTMASKCLEAR 0x08c
+#define EMAC_MACINVECTOR 0x090
+#define EMAC_MACEOIVECTOR 0x094
+#define EMAC_RXINTSTATRAW 0x0a0
+#define EMAC_RXINTSTATMASKED 0x0a4
+#define EMAC_RXINTMASKSET 0x0a8
+#define EMAC_RXINTMASKCLEAR 0x0ac
+#define EMAC_MACINTSTATRAW 0x0b0
+#define EMAC_MACINTSTATMASKED 0x0b4
+#define EMAC_MACINTMASKSET 0x0b8
+#define EMAC_MACINTMASKCLEAR 0x0bc
+#define EMAC_RXMBPENABLE 0x100
+#define EMAC_RXUNICASTSET 0x104
+#define EMAC_RXUNICASTCLEAR 0x108
+#define EMAC_RXMAXLEN 0x10c
+#define EMAC_RXBUFFEROFFSET 0x110
+#define EMAC_RXFILTERLOWTHRESH 0x114
+#define EMAC_RX0FLOWTHRESH 0x120
+#define EMAC_RX1FLOWTHRESH 0x124
+#define EMAC_RX2FLOWTHRESH 0x128
+#define EMAC_RX3FLOWTHRESH 0x12c
+#define EMAC_RX4FLOWTHRESH 0x130
+#define EMAC_RX5FLOWTHRESH 0x134
+#define EMAC_RX6FLOWTHRESH 0x138
+#define EMAC_RX7FLOWTHRESH 0x13c
+#define EMAC_RX0FREEBUFFER 0x140
+#define EMAC_RX1FREEBUFFER 0x144
+#define EMAC_RX2FREEBUFFER 0x148
+#define EMAC_RX3FREEBUFFER 0x14c
+#define EMAC_RX4FREEBUFFER 0x150
+#define EMAC_RX5FREEBUFFER 0x154
+#define EMAC_RX6FREEBUFFER 0x158
+#define EMAC_RX7FREEBUFFER 0x15c
+#define EMAC_MACCONTROL 0x160
+#define EMAC_MACSTATUS 0x164
+#define EMAC_EMCONTROL 0x168
+#define EMAC_FIFOCONTROL 0x16c
+#define EMAC_MACCONFIG 0x170
+#define EMAC_SOFTRESET 0x174
+#define EMAC_MACSRCADDRLO 0x1d0
+#define EMAC_MACSRCADDRHI 0x1d4
+#define EMAC_MACHASH1 0x1d8
+#define EMAC_MACHASH2 0x1dc
+#define EMAC_BOFFTEST 0x1e0
+#define EMAC_TPACETEST 0x1e4
+#define EMAC_RXPAUSE 0x1e8
+#define EMAC_TXPAUSE 0x1ec
+#define EMAC_RXGOODFRAMES 0x200
+#define EMAC_RXBCASTFRAMES 0x204
+#define EMAC_RXMCASTFRAMES 0x208
+#define EMAC_RXPAUSEFRAMES 0x20c
+#define EMAC_RXCRCERRORS 0x210
+#define EMAC_RXALIGNCODEERRORS 0x214
+#define EMAC_RXOVERSIZED 0x218
+#define EMAC_RXJABBER 0x21c
+#define EMAC_RXUNDERSIZED 0x220
+#define EMAC_RXFRAGMENTS 0x224
+#define EMAC_RXFILTERED 0x228
+#define EMAC_RXQOSFILTERED 0x22c
+#define EMAC_RXOCTETS 0x230
+#define EMAC_TXGOODFRAMES 0x234
+#define EMAC_TXBCASTFRAMES 0x238
+#define EMAC_TXMCASTFRAMES 0x23c
+#define EMAC_TXPAUSEFRAMES 0x240
+#define EMAC_TXDEFERRED 0x244
+#define EMAC_TXCOLLISION 0x248
+#define EMAC_TXSINGLECOLL 0x24c
+#define EMAC_TXMULTICOLL 0x250
+#define EMAC_TXEXCESSIVECOLL 0x254
+#define EMAC_TXLATECOLL 0x258
+#define EMAC_TXUNDERRUN 0x25c
+#define EMAC_TXCARRIERSENSE 0x260
+#define EMAC_TXOCTETS 0x264
+#define EMAC_FRAME64 0x268
+#define EMAC_FRAME65T127 0x26c
+#define EMAC_FRAME128T255 0x270
+#define EMAC_FRAME256T511 0x274
+#define EMAC_FRAME512T1023 0x278
+#define EMAC_FRAME1024TUP 0x27c
+#define EMAC_NETOCTETS 0x280
+#define EMAC_RXSOFOVERRUNS 0x284
+#define EMAC_RXMOFOVERRUNS 0x288
+#define EMAC_RXDMAOVERRUNS 0x28c
+#define EMAC_MACADDRLO 0x500
+#define EMAC_MACADDRHI 0x504
+#define EMAC_MACINDEX 0x508
+#define EMAC_TX0HDP 0x600
+#define EMAC_TX1HDP 0x604
+#define EMAC_TX2HDP 0x608
+#define EMAC_TX3HDP 0x60c
+#define EMAC_TX4HDP 0x610
+#define EMAC_TX5HDP 0x614
+#define EMAC_TX6HDP 0x618
+#define EMAC_TX7HDP 0x61c
+#define EMAC_RX0HDP 0x620
+#define EMAC_RX1HDP 0x624
+#define EMAC_RX2HDP 0x628
+#define EMAC_RX3HDP 0x62c
+#define EMAC_RX4HDP 0x630
+#define EMAC_RX5HDP 0x634
+#define EMAC_RX6HDP 0x638
+#define EMAC_RX7HDP 0x63c
+#define EMAC_TX0CP 0x640
+#define EMAC_TX1CP 0x644
+#define EMAC_TX2CP 0x648
+#define EMAC_TX3CP 0x64c
+#define EMAC_TX4CP 0x650
+#define EMAC_TX5CP 0x654
+#define EMAC_TX6CP 0x658
+#define EMAC_TX7CP 0x65c
+#define EMAC_RX0CP 0x660
+#define EMAC_RX1CP 0x664
+#define EMAC_RX2CP 0x668
+#define EMAC_RX3CP 0x66c
+#define EMAC_RX4CP 0x670
+#define EMAC_RX5CP 0x674
+#define EMAC_RX6CP 0x678
+#define EMAC_RX7CP 0x67c
+
+/* EMAC Wrapper Registers */
+#define EMAC_EWRAP_IDVER 0x00
+#define EMAC_EWRAP_SOFTRESET 0x04
+#define EMAC_EWRAP_INTCTRL 0x0c
+#define EMAC_EWRAP_C0RXTHRESHEN 0x10
+#define EMAC_EWRAP_C0RXEN 0x14
+#define EMAC_EWRAP_C0TXEN 0x18
+#define EMAC_EWRAP_C0MISCEN 0x1c
+#define EMAC_EWRAP_C1RXTHRESHEN 0x20
+#define EMAC_EWRAP_C1RXEN 0x24
+#define EMAC_EWRAP_C1TXEN 0x28
+#define EMAC_EWRAP_C1MISCEN 0x2c
+#define EMAC_EWRAP_C2RXTHRESHEN 0x30
+#define EMAC_EWRAP_C2RXEN 0x34
+#define EMAC_EWRAP_C2TXEN 0x38
+#define EMAC_EWRAP_C2MISCEN 0x3c
+#define EMAC_EWRAP_C0RXTHRESHSTAT 0x40
+#define EMAC_EWRAP_C0RXSTAT 0x44
+#define EMAC_EWRAP_C0TXSTAT 0x48
+#define EMAC_EWRAP_C0MISCSTAT 0x4c
+#define EMAC_EWRAP_C1RXTHRESHSTAT 0x50
+#define EMAC_EWRAP_C1RXSTAT 0x54
+#define EMAC_EWRAP_C1TXSTAT 0x58
+#define EMAC_EWRAP_C1MISCSTAT 0x5c
+#define EMAC_EWRAP_C2RXTHRESHSTAT 0x60
+#define EMAC_EWRAP_C2RXSTAT 0x64
+#define EMAC_EWRAP_C2TXSTAT 0x68
+#define EMAC_EWRAP_C2MISCSTAT 0x6c
+#define EMAC_EWRAP_C0RXIMAX 0x70
+#define EMAC_EWRAP_C0TXIMAX 0x74
+#define EMAC_EWRAP_C1RXIMAX 0x78
+#define EMAC_EWRAP_C1TXIMAX 0x7c
+#define EMAC_EWRAP_C2RXIMAX 0x80
+#define EMAC_EWRAP_C2TXIMAX 0x84
+
+/* EMAC MDIO Registers */
+#define EMAC_MDIO_VERSION 0x00
+#define EMAC_MDIO_CONTROL 0x04
+#define EMAC_MDIO_ALIVE 0x08
+#define EMAC_MDIO_LINK 0x0c
+#define EMAC_MDIO_LINKINTRAW 0x10
+#define EMAC_MDIO_LINKINTMASKED 0x14
+#define EMAC_MDIO_USERINTRAW 0x20
+#define EMAC_MDIO_USERINTMASKED 0x24
+#define EMAC_MDIO_USERINTMASKSET 0x28
+#define EMAC_MDIO_USERINTMASKCLEAR 0x2c
+#define EMAC_MDIO_USERACCESS0 0x80
+#define EMAC_MDIO_USERPHYSEL0 0x84
+#define EMAC_MDIO_USERACCESS1 0x88
+#define EMAC_MDIO_USERPHYSEL1 0x8c
+
+#endif /* _DAVINCI_EMAC_H_ */
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index 379b4e39a5..2a87d26a51 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -29,15 +29,15 @@
#include <init.h>
#include <io.h>
#include <net.h>
-#include <miidev.h>
#include <asm/mmu.h>
#include <net/designware.h>
+#include <linux/phy.h>
#include "designware.h"
struct dw_eth_dev {
struct eth_device netdev;
- struct mii_device miidev;
+ struct mii_bus miibus;
void (*fix_mac_speed)(int speed);
u8 macaddr[6];
@@ -52,6 +52,7 @@ struct dw_eth_dev {
struct eth_mac_regs *mac_regs_p;
struct eth_dma_regs *dma_regs_p;
+ int phy_addr;
};
/* Speed specific definitions */
@@ -64,9 +65,9 @@ struct dw_eth_dev {
#define FULL_DUPLEX 2
-static int dwc_ether_mii_read(struct mii_device *dev, int addr, int reg)
+static int dwc_ether_mii_read(struct mii_bus *dev, int addr, int reg)
{
- struct dw_eth_dev *priv = dev->edev->priv;
+ struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
u64 start;
u32 miiaddr;
@@ -86,9 +87,9 @@ static int dwc_ether_mii_read(struct mii_device *dev, int addr, int reg)
return readl(&mac_p->miidata) & 0xffff;
}
-static int dwc_ether_mii_write(struct mii_device *dev, int addr, int reg, int val)
+static int dwc_ether_mii_write(struct mii_bus *dev, int addr, int reg, u16 val)
{
- struct dw_eth_dev *priv = dev->edev->priv;
+ struct dw_eth_dev *priv = dev->priv;
struct eth_mac_regs *mac_p = priv->mac_regs_p;
u64 start;
u32 miiaddr;
@@ -222,34 +223,37 @@ static int dwc_ether_init(struct eth_device *dev)
return 0;
}
-static int dwc_ether_open(struct eth_device *dev)
+static void dwc_update_linkspeed(struct eth_device *edev)
{
- struct dw_eth_dev *priv = dev->priv;
- struct eth_mac_regs *mac_p = priv->mac_regs_p;
- struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ struct dw_eth_dev *priv = edev->priv;
u32 conf;
- int link, speed;
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
- link = miidev_get_status(&priv->miidev);
-
- if (priv->fix_mac_speed) {
- speed = link & MIIDEV_STATUS_IS_1000MBIT ? 1000 :
- (link & MIIDEV_STATUS_IS_100MBIT ? 100 : 10);
- priv->fix_mac_speed(speed);
- }
+ if (priv->fix_mac_speed)
+ priv->fix_mac_speed(edev->phydev->speed);
conf = readl(&mac_p->conf);
- if (link & MIIDEV_STATUS_IS_FULL_DUPLEX)
+ if (edev->phydev->duplex)
conf |= FULLDPLXMODE;
else
conf &= ~FULLDPLXMODE;
- if (link & MIIDEV_STATUS_IS_1000MBIT)
+ if (edev->phydev->speed == SPEED_1000)
conf &= ~MII_PORTSELECT;
else
conf |= MII_PORTSELECT;
writel(conf, &mac_p->conf);
+}
+
+static int dwc_ether_open(struct eth_device *dev)
+{
+ struct dw_eth_dev *priv = dev->priv;
+ struct eth_mac_regs *mac_p = priv->mac_regs_p;
+ struct eth_dma_regs *dma_p = priv->dma_regs_p;
+ int ret;
+
+ ret = phy_device_connect(dev, &priv->miibus, priv->phy_addr,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
descs_init(dev);
@@ -373,7 +377,7 @@ static int dwc_ether_probe(struct device_d *dev)
{
struct dw_eth_dev *priv;
struct eth_device *edev;
- struct mii_device *miidev;
+ struct mii_bus *miibus;
void __iomem *base;
struct dwc_ether_platform_data *pdata = dev->platform_data;
@@ -397,7 +401,7 @@ static int dwc_ether_probe(struct device_d *dev)
priv->fix_mac_speed = pdata->fix_mac_speed;
edev = &priv->netdev;
- miidev = &priv->miidev;
+ miibus = &priv->miibus;
edev->priv = priv;
edev->init = dwc_ether_init;
@@ -408,12 +412,12 @@ static int dwc_ether_probe(struct device_d *dev)
edev->get_ethaddr = dwc_ether_get_ethaddr;
edev->set_ethaddr = dwc_ether_set_ethaddr;
- miidev->address = pdata->phy_addr;
- miidev->read = dwc_ether_mii_read;
- miidev->write = dwc_ether_mii_write;
- miidev->edev = edev;
+ priv->phy_addr = pdata->phy_addr;
+ miibus->read = dwc_ether_mii_read;
+ miibus->write = dwc_ether_mii_write;
+ miibus->priv = priv;
- mii_register(miidev);
+ mdiobus_register(miibus);
eth_register(edev);
return 0;
}
diff --git a/drivers/net/dm9k.c b/drivers/net/dm9k.c
index 0222d98f7b..ac18be26c0 100644
--- a/drivers/net/dm9k.c
+++ b/drivers/net/dm9k.c
@@ -26,12 +26,12 @@
#include <init.h>
#include <common.h>
#include <driver.h>
-#include <miidev.h>
#include <net.h>
#include <io.h>
#include <xfuncs.h>
#include <dm9000.h>
#include <errno.h>
+#include <linux/phy.h>
#define DM9K_ID 0x90000A46
#define CHIPR_DM9000A 0x19
@@ -160,7 +160,7 @@
struct dm9k {
void __iomem *iobase;
void __iomem *iodata;
- struct mii_device miidev;
+ struct mii_bus miibus;
int buswidth;
int srom;
uint8_t pckt[2048];
@@ -353,12 +353,11 @@ static void dm9k_wd(int b_width, void __iomem *port, const void *src, int length
/* ----------------- end of data move functions -------------------------- */
-static int dm9k_phy_read(struct mii_device *mdev, int addr, int reg)
+static int dm9k_phy_read(struct mii_bus *bus, int addr, int reg)
{
unsigned val;
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct dm9k *priv = edev->priv;
+ struct dm9k *priv = bus->priv;
+ struct device_d *dev = &bus->dev;
/* Fill the phyxcer register into REG_0C */
dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
@@ -374,11 +373,10 @@ static int dm9k_phy_read(struct mii_device *mdev, int addr, int reg)
return val;
}
-static int dm9k_phy_write(struct mii_device *mdev, int addr, int reg, int val)
+static int dm9k_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct dm9k *priv = edev->priv;
+ struct dm9k *priv = bus->priv;
+ struct device_d *dev = &bus->dev;
/* Fill the phyxcer register into REG_0C */
dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg);
@@ -397,7 +395,7 @@ static int dm9k_phy_write(struct mii_device *mdev, int addr, int reg, int val)
static int dm9k_check_id(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
u32 id;
char c;
@@ -461,7 +459,7 @@ static void dm9k_enable(struct dm9k *priv)
static void dm9k_reset(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
dev_dbg(dev, "%s\n", __func__);
dm9k_iow(priv, DM9K_NCR, NCR_RST);
@@ -472,9 +470,8 @@ static int dm9k_eth_open(struct eth_device *edev)
{
struct dm9k *priv = (struct dm9k *)edev->priv;
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
- return 0;
+ return phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static void dm9k_write_length(struct dm9k *priv, unsigned length)
@@ -485,7 +482,7 @@ static void dm9k_write_length(struct dm9k *priv, unsigned length)
static int dm9k_wait_for_trans_end(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
static const uint64_t toffs = 1 * SECOND;
uint8_t status;
uint64_t start = get_time_ns();
@@ -511,7 +508,7 @@ static int dm9k_wait_for_trans_end(struct dm9k *priv)
static int dm9k_eth_send(struct eth_device *edev, void *packet, int length)
{
struct dm9k *priv = (struct dm9k *)edev->priv;
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
dev_dbg(dev, "%s: %d bytes\n", __func__, length);
@@ -537,7 +534,7 @@ static int dm9k_eth_send(struct eth_device *edev, void *packet, int length)
static int dm9k_check_for_rx_packet(struct dm9k *priv)
{
uint8_t status;
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
status = dm9k_ior(priv, DM9K_ISR);
if (!(status & ISR_PR))
@@ -550,7 +547,7 @@ static int dm9k_check_for_rx_packet(struct dm9k *priv)
static int dm9k_validate_entry(struct dm9k *priv)
{
- struct device_d *dev = priv->miidev.parent;
+ struct device_d *dev = priv->miibus.parent;
uint8_t p_stat;
/*
@@ -696,9 +693,6 @@ static int dm9k_set_ethaddr(struct eth_device *edev, unsigned char *adr)
static int dm9k_init_dev(struct eth_device *edev)
{
- struct dm9k *priv = (struct dm9k *)edev->priv;
-
- miidev_restart_aneg(&priv->miidev);
return 0;
}
@@ -740,12 +734,10 @@ static int dm9k_probe(struct device_d *dev)
edev->get_ethaddr = dm9k_get_ethaddr;
edev->parent = dev;
- priv->miidev.read = dm9k_phy_read;
- priv->miidev.write = dm9k_phy_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = dm9k_phy_read;
+ priv->miibus.write = dm9k_phy_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
/* RESET device */
dm9k_reset(priv);
@@ -778,7 +770,7 @@ static int dm9k_probe(struct device_d *dev)
dm9k_enable(priv);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/ep93xx.c b/drivers/net/ep93xx.c
index c28fb79e45..a14c0ea8e3 100644
--- a/drivers/net/ep93xx.c
+++ b/drivers/net/ep93xx.c
@@ -34,17 +34,17 @@
#include <command.h>
#include <init.h>
#include <malloc.h>
-#include <miidev.h>
#include <io.h>
#include <linux/types.h>
#include <mach/ep93xx-regs.h>
+#include <linux/phy.h>
#include "ep93xx.h"
#define EP93XX_MAX_PKT_SIZE 1536
-static int ep93xx_phy_read(struct mii_device *mdev, int phy_addr, int phy_reg);
-static int ep93xx_phy_write(struct mii_device *mdev, int phy_addr, int phy_reg,
- int value);
+static int ep93xx_phy_read(struct mii_bus *bus, int phy_addr, int phy_reg);
+static int ep93xx_phy_write(struct mii_bus *bus, int phy_addr, int phy_reg,
+ u16 value);
static inline struct ep93xx_eth_priv *ep93xx_get_priv(struct eth_device *edev)
{
@@ -199,9 +199,15 @@ static int ep93xx_eth_open(struct eth_device *edev)
struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev);
struct mac_regs *regs = ep93xx_get_regs(edev);
int i;
+ int ret;
pr_debug("+ep93xx_eth_open\n");
+ ret = phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
+
ep93xx_eth_reset(edev);
/* Reset the descriptor queues' current and end address values */
@@ -498,11 +504,10 @@ static int ep93xx_eth_probe(struct device_d *dev)
edev->set_ethaddr = ep93xx_eth_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = ep93xx_phy_read;
- priv->miidev.write = ep93xx_phy_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.parent = dev;
+ priv->miibus.read = ep93xx_phy_read;
+ priv->miibus.write = ep93xx_phy_write;
+ priv->miibus.parent = dev;
+ priv->miibus.priv = edev;
priv->tx_dq.base = calloc(NUMTXDESC,
sizeof(struct tx_descriptor));
@@ -532,7 +537,7 @@ static int ep93xx_eth_probe(struct device_d *dev)
goto eth_probe_failed_3;
}
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
ret = 0;
@@ -575,9 +580,9 @@ eth_probe_done:
/**
* Read a 16-bit value from an MII register.
*/
-static int ep93xx_phy_read(struct mii_device *mdev, int phy_addr, int phy_reg)
+static int ep93xx_phy_read(struct mii_bus *bus, int phy_addr, int phy_reg)
{
- struct mac_regs *regs = ep93xx_get_regs(mdev->edev);
+ struct mac_regs *regs = ep93xx_get_regs(bus->priv);
int value = -1;
uint32_t self_ctl;
@@ -618,10 +623,10 @@ static int ep93xx_phy_read(struct mii_device *mdev, int phy_addr, int phy_reg)
/**
* Write a 16-bit value to an MII register.
*/
-static int ep93xx_phy_write(struct mii_device *mdev, int phy_addr,
- int phy_reg, int value)
+static int ep93xx_phy_write(struct mii_bus *bus, int phy_addr,
+ int phy_reg, u16 value)
{
- struct mac_regs *regs = ep93xx_get_regs(mdev->edev);
+ struct mac_regs *regs = ep93xx_get_regs(bus->priv);
uint32_t self_ctl;
pr_debug("+ep93xx_phy_write\n");
diff --git a/drivers/net/ep93xx.h b/drivers/net/ep93xx.h
index 47622d6a24..89451b8a5f 100644
--- a/drivers/net/ep93xx.h
+++ b/drivers/net/ep93xx.h
@@ -137,7 +137,7 @@ struct ep93xx_eth_priv {
struct tx_descriptor_queue tx_dq;
struct tx_status_queue tx_sq;
- struct mii_device miidev;
+ struct mii_bus miibus;
};
#endif
diff --git a/drivers/net/fec_imx.c b/drivers/net/fec_imx.c
index c80cdc96a5..6acf6bdee4 100644
--- a/drivers/net/fec_imx.c
+++ b/drivers/net/fec_imx.c
@@ -19,11 +19,11 @@
#include <net.h>
#include <init.h>
#include <driver.h>
-#include <miidev.h>
#include <fec.h>
#include <io.h>
#include <clock.h>
#include <xfuncs.h>
+#include <linux/phy.h>
#include <asm/mmu.h>
@@ -46,10 +46,9 @@ struct fec_frame {
/*
* MII-interface related functions
*/
-static int fec_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr)
+static int fec_miibus_read(struct mii_bus *bus, int phyAddr, int regAddr)
{
- struct eth_device *edev = mdev->edev;
- struct fec_priv *fec = (struct fec_priv *)edev->priv;
+ struct fec_priv *fec = (struct fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -89,11 +88,10 @@ static int fec_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr)
return readl(fec->regs + FEC_MII_DATA);
}
-static int fec_miidev_write(struct mii_device *mdev, int phyAddr,
- int regAddr, int data)
+static int fec_miibus_write(struct mii_bus *bus, int phyAddr,
+ int regAddr, u16 data)
{
- struct eth_device *edev = mdev->edev;
- struct fec_priv *fec = (struct fec_priv *)edev->priv;
+ struct fec_priv *fec = (struct fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -343,12 +341,20 @@ static int fec_init(struct eth_device *dev)
/* size of each buffer */
writel(FEC_MAX_PKT_SIZE, fec->regs + FEC_EMRBR);
- if (fec->xcv_type != SEVENWIRE)
- miidev_restart_aneg(&fec->miidev);
-
return 0;
}
+static void fec_update_linkspeed(struct eth_device *edev)
+{
+ struct fec_priv *fec = (struct fec_priv *)edev->priv;
+
+ if (edev->phydev->speed == SPEED_10) {
+ u32 rcntl = readl(fec->regs + FEC_R_CNTRL);
+ rcntl |= FEC_R_CNTRL_RMII_10T;
+ writel(rcntl, fec->regs + FEC_R_CNTRL);
+ }
+}
+
/**
* Start the FEC engine
* @param[in] edev Our device to handle
@@ -359,6 +365,17 @@ static int fec_open(struct eth_device *edev)
int ret;
u32 ecr;
+ if (fec->xcv_type != SEVENWIRE) {
+ ret = phy_device_connect(edev, &fec->miibus, fec->phy_addr,
+ fec_update_linkspeed, fec->phy_flags,
+ fec->interface);
+ if (ret)
+ return ret;
+
+ if (fec->phy_init)
+ fec->phy_init(edev->phydev);
+ }
+
/*
* Initialize RxBD/TxBD rings
*/
@@ -384,24 +401,6 @@ static int fec_open(struct eth_device *edev)
*/
fec_rx_task_enable(fec);
- if (fec->xcv_type != SEVENWIRE) {
- ret = miidev_wait_aneg(&fec->miidev);
- if (ret)
- return ret;
-
- ret = miidev_get_status(&fec->miidev);
- if (ret < 0)
- return ret;
-
- if (ret & MIIDEV_STATUS_IS_10MBIT) {
- u32 rcntl = readl(fec->regs + FEC_R_CNTRL);
- rcntl |= FEC_R_CNTRL_RMII_10T;
- writel(rcntl, fec->regs + FEC_R_CNTRL);
- }
-
- miidev_print_status(&fec->miidev);
- }
-
return 0;
}
@@ -655,14 +654,30 @@ static int fec_probe(struct device_d *dev)
fec->xcv_type = pdata->xcv_type;
if (fec->xcv_type != SEVENWIRE) {
- fec->miidev.read = fec_miidev_read;
- fec->miidev.write = fec_miidev_write;
- fec->miidev.address = pdata->phy_addr;
- fec->miidev.flags = pdata->xcv_type == MII10 ? MIIDEV_FORCE_10 : 0;
- fec->miidev.edev = edev;
- fec->miidev.parent = dev;
-
- mii_register(&fec->miidev);
+ fec->phy_init = pdata->phy_init;
+ fec->miibus.read = fec_miibus_read;
+ fec->miibus.write = fec_miibus_write;
+ fec->phy_addr = pdata->phy_addr;
+ switch (pdata->xcv_type) {
+ case RMII:
+ fec->interface = PHY_INTERFACE_MODE_RMII;
+ break;
+ case RGMII:
+ fec->interface = PHY_INTERFACE_MODE_RGMII;
+ break;
+ case MII10:
+ fec->phy_flags = PHYLIB_FORCE_10;
+ case MII100:
+ fec->interface = PHY_INTERFACE_MODE_MII;
+ break;
+ case SEVENWIRE:
+ fec->interface = PHY_INTERFACE_MODE_NA;
+ break;
+ }
+ fec->miibus.priv = fec;
+ fec->miibus.parent = dev;
+
+ mdiobus_register(&fec->miibus);
}
eth_register(edev);
diff --git a/drivers/net/fec_imx.h b/drivers/net/fec_imx.h
index b979f12a5b..d10385a531 100644
--- a/drivers/net/fec_imx.h
+++ b/drivers/net/fec_imx.h
@@ -133,7 +133,11 @@ struct fec_priv {
int rbd_index; /* next receive BD to read */
struct buffer_descriptor __iomem *tbd_base; /* TBD ring */
int tbd_index; /* next transmit BD to write */
- struct mii_device miidev;
+ int phy_addr;
+ phy_interface_t interface;
+ u32 phy_flags;
+ struct mii_bus miibus;
+ void (*phy_init)(struct phy_device *dev);
};
/**
diff --git a/drivers/net/fec_mpc5200.c b/drivers/net/fec_mpc5200.c
index c3f2099b0f..c42d86f513 100644
--- a/drivers/net/fec_mpc5200.c
+++ b/drivers/net/fec_mpc5200.c
@@ -10,13 +10,12 @@
#include <mach/mpc5xxx.h>
#include <malloc.h>
#include <net.h>
+#include <fec.h>
#include <init.h>
-#include <miidev.h>
#include <driver.h>
#include <mach/sdma.h>
-#include <mach/fec.h>
#include <mach/clocks.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include "fec_mpc5200.h"
#define CONFIG_PHY_ADDR 1 /* FIXME */
@@ -31,10 +30,9 @@ typedef struct {
/*
* MII-interface related functions
*/
-static int fec5xxx_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr)
+static int fec5xxx_miibus_read(struct mii_bus *bus, int phyAddr, int regAddr)
{
- struct eth_device *edev = mdev->edev;
- mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)edev->priv;
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -70,11 +68,10 @@ static int fec5xxx_miidev_read(struct mii_device *mdev, int phyAddr, int regAddr
return fec->eth->mii_data;
}
-static int fec5xxx_miidev_write(struct mii_device *mdev, int phyAddr,
- int regAddr, int data)
+static int fec5xxx_miibus_write(struct mii_bus *bus, int phyAddr,
+ int regAddr, u16 data)
{
- struct eth_device *edev = mdev->edev;
- mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)edev->priv;
+ mpc5xxx_fec_priv *fec = (mpc5xxx_fec_priv *)bus->priv;
uint32_t reg; /* convenient holder for the PHY register */
uint32_t phy; /* convenient holder for the PHY */
@@ -381,9 +378,6 @@ static int mpc5xxx_fec_init(struct eth_device *dev)
debug("mpc5xxx_fec_init... Done \n");
- if (fec->xcv_type != SEVENWIRE)
- miidev_restart_aneg(&fec->miidev);
-
return 0;
}
@@ -413,8 +407,8 @@ static int mpc5xxx_fec_open(struct eth_device *edev)
SDMA_TASK_ENABLE(FEC_RECV_TASK_NO);
if (fec->xcv_type != SEVENWIRE) {
- miidev_wait_aneg(&fec->miidev);
- miidev_print_status(&fec->miidev);
+ return phy_device_connect(edev, &fec->miibus, CONFIG_PHY_ADDR,
+ NULL, fec->phy_flags, fec->interface);
}
return 0;
@@ -556,7 +550,7 @@ static int mpc5xxx_fec_send(struct eth_device *dev, void *eth_data,
*/
if (fec->xcv_type != SEVENWIRE) {
uint16_t phyStatus;
- phyStatus = fec5xxx_miidev_read(&fec->miidev, 0, 0x1);
+ phyStatus = fec5xxx_miibus_read(&fec->miibus, 0, 0x1);
}
/*
@@ -657,7 +651,7 @@ static int mpc5xxx_fec_recv(struct eth_device *dev)
int mpc5xxx_fec_probe(struct device_d *dev)
{
- struct mpc5xxx_fec_platform_data *pdata = (struct mpc5xxx_fec_platform_data *)dev->platform_data;
+ struct fec_platform_data *pdata = dev->platform_data;
struct eth_device *edev;
mpc5xxx_fec_priv *fec;
@@ -683,14 +677,28 @@ int mpc5xxx_fec_probe(struct device_d *dev)
loadtask(0, 2);
if (fec->xcv_type != SEVENWIRE) {
- fec->miidev.read = fec5xxx_miidev_read;
- fec->miidev.write = fec5xxx_miidev_write;
- fec->miidev.address = CONFIG_PHY_ADDR;
- fec->miidev.flags = pdata->xcv_type == MII10 ? MIIDEV_FORCE_10 : 0;
- fec->miidev.edev = edev;
- fec->miidev.parent = dev;
-
- mii_register(&fec->miidev);
+ fec->miibus.read = fec5xxx_miibus_read;
+ fec->miibus.write = fec5xxx_miibus_write;
+ switch (pdata->xcv_type) {
+ case RMII:
+ fec->interface = PHY_INTERFACE_MODE_RMII;
+ break;
+ case RGMII:
+ fec->interface = PHY_INTERFACE_MODE_RGMII;
+ break;
+ case MII10:
+ fec->phy_flags = PHYLIB_FORCE_10;
+ case MII100:
+ fec->interface = PHY_INTERFACE_MODE_MII;
+ break;
+ case SEVENWIRE:
+ fec->interface = PHY_INTERFACE_MODE_NA;
+ break;
+ }
+ fec->miibus.priv = fec;
+ fec->miibus.parent = dev;
+
+ mdiobus_register(&fec->miibus);
}
eth_register(edev);
diff --git a/drivers/net/fec_mpc5200.h b/drivers/net/fec_mpc5200.h
index f6da3e598f..20ac60731c 100644
--- a/drivers/net/fec_mpc5200.h
+++ b/drivers/net/fec_mpc5200.h
@@ -260,7 +260,9 @@ typedef struct {
uint16_t usedTbdIndex; /* next transmit BD to clean */
uint16_t cleanTbdNum; /* the number of available transmit BDs */
- struct mii_device miidev;
+ phy_interface_t interface;
+ u32 phy_flags;
+ struct mii_bus miibus;
} mpc5xxx_fec_priv;
/* Ethernet parameter area */
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 19544de261..20fd102c7e 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -17,10 +17,10 @@
#include <net.h>
#include <init.h>
#include <driver.h>
-#include <miidev.h>
#include <command.h>
#include <errno.h>
#include <asm/io.h>
+#include <linux/phy.h>
#include "gianfar.h"
/* 2 seems to be the minimum number of TX descriptors to make it work. */
@@ -80,22 +80,16 @@ static void gfar_init_registers(void __iomem *regs)
static void gfar_adjust_link(struct eth_device *edev)
{
struct gfar_private *priv = edev->priv;
- struct device_d *mdev = priv->miidev.parent;
void __iomem *regs = priv->regs;
u32 ecntrl, maccfg2;
uint32_t status;
- status = miidev_get_status(&priv->miidev);
+ priv->link = edev->phydev->link;
+ priv->duplexity =edev->phydev->duplex;
- priv->link = status & MIIDEV_STATUS_IS_UP;
- if (status & MIIDEV_STATUS_IS_FULL_DUPLEX)
- priv->duplexity = 1;
- else
- priv->duplexity = 0;
-
- if (status & MIIDEV_STATUS_IS_1000MBIT)
+ if (edev->phydev->speed == SPEED_1000)
priv->speed = 1000;
- else if (status & MIIDEV_STATUS_IS_100MBIT)
+ if (edev->phydev->speed == SPEED_100)
priv->speed = 100;
else
priv->speed = 10;
@@ -128,18 +122,18 @@ static void gfar_adjust_link(struct eth_device *edev)
ecntrl |= GFAR_ECNTRL_R100;
break;
default:
- dev_info(mdev, "Speed is unknown\n");
+ dev_info(&edev->dev, "Speed is unknown\n");
break;
}
out_be32(regs + GFAR_ECNTRL_OFFSET, ecntrl);
out_be32(regs + GFAR_MACCFG2_OFFSET, maccfg2);
- dev_info(mdev, "Speed: %d, %s duplex\n", priv->speed,
+ dev_info(&edev->dev, "Speed: %d, %s duplex\n", priv->speed,
(priv->duplexity) ? "full" : "half");
} else {
- dev_info(mdev, "No link.\n");
+ dev_info(&edev->dev, "No link.\n");
}
}
@@ -184,8 +178,6 @@ static int gfar_init(struct eth_device *edev)
gfar_init_registers(regs);
- miidev_restart_aneg(&priv->miidev);
-
return 0;
}
@@ -194,6 +186,12 @@ static int gfar_open(struct eth_device *edev)
int ix;
struct gfar_private *priv = edev->priv;
void __iomem *regs = priv->regs;
+ int ret;
+
+ ret = phy_device_connect(edev, &priv->miibus, priv->phyaddr,
+ gfar_adjust_link, 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
/* Point to the buffer descriptors */
out_be32(regs + GFAR_TBASE0_OFFSET, (unsigned int)priv->txbd);
@@ -215,9 +213,6 @@ static int gfar_open(struct eth_device *edev)
}
priv->txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP;
- miidev_wait_aneg(&priv->miidev);
- gfar_adjust_link(edev);
-
/* Enable Transmit and Receive */
setbits_be32(regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_RX_EN |
GFAR_MACCFG1_TX_EN);
@@ -437,11 +432,10 @@ static int gfar_recv(struct eth_device *edev)
}
/* Read a MII PHY register. */
-static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
+static int gfar_miiphy_read(struct mii_bus *bus, int addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct gfar_private *priv = edev->priv;
+ struct device_d *dev = bus->parent;
+ struct gfar_private *priv = bus->priv;
int ret;
ret = gfar_local_mdio_read(priv->phyregs, addr, reg);
@@ -452,12 +446,11 @@ static int gfar_miiphy_read(struct mii_device *mdev, int addr, int reg)
}
/* Write a MII PHY register. */
-static int gfar_miiphy_write(struct mii_device *mdev, int addr, int reg,
- int value)
+static int gfar_miiphy_write(struct mii_bus *bus, int addr, int reg,
+ u16 value)
{
- struct eth_device *edev = mdev->edev;
- struct device_d *dev = edev->parent;
- struct gfar_private *priv = edev->priv;
+ struct device_d *dev = bus->parent;
+ struct gfar_private *priv = bus->priv;
unsigned short val = value;
int ret;
@@ -520,16 +513,14 @@ static int gfar_probe(struct device_d *dev)
udelay(2);
clrbits_be32(priv->regs + GFAR_MACCFG1_OFFSET, GFAR_MACCFG1_SOFT_RESET);
- priv->miidev.read = gfar_miiphy_read;
- priv->miidev.write = gfar_miiphy_write;
- priv->miidev.address = priv->phyaddr;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = gfar_miiphy_read;
+ priv->miibus.write = gfar_miiphy_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
gfar_init_phy(edev);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
return eth_register(edev);
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index a4ad99e3b7..b52cc5ab3b 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -269,7 +269,7 @@ struct gfar_private {
void __iomem *phyregs;
void __iomem *phyregs_sgmii;
struct phy_info *phyinfo;
- struct mii_device miidev;
+ struct mii_bus miibus;
volatile struct txbd8 *txbd;
volatile struct rxbd8 *rxbd;
uint txidx;
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c
index ba4b8c3b14..c48e729dce 100644
--- a/drivers/net/ks8851_mll.c
+++ b/drivers/net/ks8851_mll.c
@@ -22,13 +22,13 @@
#include <command.h>
#include <net.h>
-#include <miidev.h>
#include <malloc.h>
#include <init.h>
#include <xfuncs.h>
#include <errno.h>
#include <clock.h>
#include <io.h>
+#include <linux/phy.h>
#define MAX_RECV_FRAMES 32
#define MAX_BUF_SIZE 2048
@@ -368,7 +368,7 @@
struct ks_net {
struct eth_device edev;
- struct mii_device miidev;
+ struct mii_bus miibus;
void __iomem *hw_addr;
void __iomem *hw_addr_cmd;
struct platform_device *pdev;
@@ -532,10 +532,9 @@ static int ks_phy_reg(int reg)
* caller. The mii-tool that the driver was tested with takes any -ve error
* as real PHY capabilities, thus displaying incorrect data to the user.
*/
-static int ks_phy_read(struct mii_device *mdev, int addr, int reg)
+static int ks_phy_read(struct mii_bus *bus, int addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct ks_net *priv = (struct ks_net *)edev->priv;
+ struct ks_net *priv = (struct ks_net *)bus->priv;
int ksreg;
int result;
@@ -548,10 +547,9 @@ static int ks_phy_read(struct mii_device *mdev, int addr, int reg)
return result;
}
-static int ks_phy_write(struct mii_device *mdev, int addr, int reg, int val)
+static int ks_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
- struct ks_net *priv = (struct ks_net *)edev->priv;
+ struct ks_net *priv = (struct ks_net *)bus->priv;
int ksreg;
ksreg = ks_phy_reg(reg);
@@ -779,11 +777,14 @@ static int ks8851_eth_open(struct eth_device *edev)
{
struct ks_net *priv = (struct ks_net *)edev->priv;
struct device_d *dev = &edev->dev;
+ int ret;
ks_enable_qmu(priv);
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
+ ret = phy_device_connect(edev, &priv->miibus, 1, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
dev_dbg(dev, "eth_open\n");
@@ -792,9 +793,6 @@ static int ks8851_eth_open(struct eth_device *edev)
static int ks8851_init_dev(struct eth_device *edev)
{
- struct ks_net *priv = (struct ks_net *)edev->priv;
-
- miidev_restart_aneg(&priv->miidev);
return 0;
}
@@ -838,12 +836,10 @@ static int ks8851_probe(struct device_d *dev)
edev->parent = dev;
/* setup mii state */
- ks->miidev.read = ks_phy_read;
- ks->miidev.write = ks_phy_write;
- ks->miidev.address = 1;
- ks->miidev.flags = 0;
- ks->miidev.edev = edev;
- ks->miidev.parent = dev;
+ ks->miibus.read = ks_phy_read;
+ ks->miibus.write = ks_phy_write;
+ ks->miibus.priv = ks;
+ ks->miibus.parent = dev;
/* simple check for a valid chip being connected to the bus */
@@ -864,7 +860,7 @@ static int ks8851_probe(struct device_d *dev)
ks_soft_reset(ks, GRR_GSR);
ks_setup(ks);
- mii_register(&ks->miidev);
+ mdiobus_register(&ks->miibus);
eth_register(edev);
dev_dbg(dev, "%s MARL 0x%04x MARM 0x%04x MARH 0x%04x\n", __func__,
ks_rdreg16(ks, KS_MARL), ks_rdreg16(ks, KS_MARM),
diff --git a/drivers/net/ksz8864rmn.c b/drivers/net/ksz8864rmn.c
new file mode 100644
index 0000000000..5845960f6c
--- /dev/null
+++ b/drivers/net/ksz8864rmn.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2012 Jan Luebbe, Pengutronix
+ *
+ * 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 <init.h>
+#include <driver.h>
+#include <spi/spi.h>
+#include <errno.h>
+
+#define REG_ID0 0x00
+#define REG_ID1 0x01
+
+#define REG_GC00 0x02
+#define REG_GC01 0x03
+#define REG_GC02 0x04
+#define REG_GC03 0x05
+#define REG_GC04 0x06
+#define REG_GC05 0x07
+#define REG_GC06 0x08
+#define REG_GC07 0x09
+#define REG_GC08 0x0a
+#define REG_GC09 0x0b
+#define REG_GC10 0x0c
+#define REG_GC11 0x0d
+
+#define REG_PSTAT1(p) (0x10 * p + 0xe)
+#define REG_PSTAT2(p) (0x10 * p + 0xf)
+
+#define CMD_WRITE 0x02
+#define CMD_READ 0x03
+
+struct micrel_switch_priv {
+ struct cdev cdev;
+ struct spi_device *spi;
+};
+
+static int micrel_switch_read_reg(struct spi_device *spi, uint8_t reg)
+{
+ uint8_t tx[2];
+ uint8_t rx[1];
+ int ret;
+
+ tx[0] = CMD_READ;
+ tx[1] = reg;
+
+ ret = spi_write_then_read(spi, tx, 2, rx, 1);
+ if (ret < 0)
+ return ret;
+
+ return rx[0];
+}
+
+static void micrel_switch_write_reg(struct spi_device *spi, uint8_t reg, uint8_t val)
+{
+ uint8_t tx[3];
+
+ tx[0] = CMD_WRITE;
+ tx[1] = reg;
+ tx[2] = val;
+
+ spi_write_then_read(spi, tx, 3, NULL, 0);
+}
+
+static int micrel_switch_enable_set(struct device_d *dev, struct param_d *param,
+ const char *val)
+{
+ struct spi_device *spi = (struct spi_device *)dev->type_data;
+ int enable;
+ char *new;
+
+ if (!val)
+ return dev_param_set_generic(dev, param, NULL);
+
+ enable = simple_strtoul(val, NULL, 0);
+
+ if (enable) {
+ micrel_switch_write_reg(spi, REG_ID1, 1);
+ new = "1";
+ } else {
+ micrel_switch_write_reg(spi, REG_ID1, 0);
+ new = "0";
+ }
+
+ dev_param_set_generic(dev, param, new);
+
+ return 0;
+}
+
+static ssize_t micel_switch_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i, ret;
+ uint8_t *buf = _buf;
+ struct micrel_switch_priv *priv = cdev->priv;
+
+ for (i = 0; i < count; i++) {
+ ret = micrel_switch_read_reg(priv->spi, offset);
+ if (ret < 0)
+ return ret;
+ *buf = ret;
+ buf++;
+ offset++;
+ }
+
+ return count;
+}
+
+static ssize_t micel_switch_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i;
+ const uint8_t *buf = _buf;
+ struct micrel_switch_priv *priv = cdev->priv;
+
+ for (i = 0; i < count; i++) {
+ micrel_switch_write_reg(priv->spi, offset, *buf);
+ buf++;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations micrel_switch_ops = {
+ .read = micel_switch_read,
+ .write = micel_switch_write,
+ .lseek = dev_lseek_default,
+};
+
+static int micrel_switch_probe(struct device_d *dev)
+{
+ struct micrel_switch_priv *priv;
+ int ret = 0;
+
+ priv = xzalloc(sizeof(*priv));
+
+ dev->priv = priv;
+
+ priv->spi = (struct spi_device *)dev->type_data;
+ priv->spi->mode = SPI_MODE_0;
+ priv->spi->bits_per_word = 8;
+
+ ret = micrel_switch_read_reg(priv->spi, REG_ID0);
+ if (ret < 0) {
+ dev_err(&priv->spi->dev, "failed to read device id\n");
+ return ret;
+ }
+ if (ret != 0x95) {
+ dev_err(&priv->spi->dev, "unknown device id: %02x\n", ret);
+ return -ENODEV;
+ }
+
+ priv->cdev.name = asprintf("switch%d", dev->id);
+ priv->cdev.size = 256;
+ priv->cdev.ops = &micrel_switch_ops;
+ priv->cdev.priv = priv;
+ priv->cdev.dev = dev;
+ devfs_create(&priv->cdev);
+
+ dev_add_param(dev, "enable", micrel_switch_enable_set, NULL, 0);
+ dev_set_param(dev, "enable", "1");
+
+ return 0;
+}
+
+static struct driver_d micrel_switch_driver = {
+ .name = "ksz8864rmn",
+ .probe = micrel_switch_probe,
+};
+
+static int micrel_switch_init(void)
+{
+ spi_register_driver(&micrel_switch_driver);
+ return 0;
+}
+device_initcall(micrel_switch_init);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 53a3ed2ceb..64970ba09f 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -41,13 +41,13 @@
#include <malloc.h>
#include <xfuncs.h>
#include <init.h>
-#include <miidev.h>
#include <errno.h>
#include <io.h>
#include <mach/board.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <asm/mmu.h>
+#include <linux/phy.h>
#include "macb.h"
@@ -94,12 +94,16 @@ struct macb_device {
struct macb_dma_desc *rx_ring;
struct macb_dma_desc *tx_ring;
+ int phy_addr;
+
const struct device *dev;
struct eth_device netdev;
- struct mii_device miidev;
+ phy_interface_t interface;
+
+ struct mii_bus miibus;
- unsigned int flags;
+ unsigned int phy_flags;
};
static int macb_send(struct eth_device *edev, void *packet,
@@ -211,26 +215,32 @@ static int macb_recv(struct eth_device *edev)
return 0;
}
-static int macb_open(struct eth_device *edev)
+static void macb_adjust_link(struct eth_device *edev)
{
struct macb_device *macb = edev->priv;
- int duplex = 1, speed = 1;
- u32 ncfgr;
+ u32 reg;
- debug("%s\n", __func__);
+ reg = readl(macb->regs + MACB_NCFGR);
+ reg &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
- miidev_wait_aneg(&macb->miidev);
- miidev_print_status(&macb->miidev);
+ if (edev->phydev->duplex)
+ reg |= MACB_BIT(FD);
+ if (edev->phydev->speed == SPEED_100)
+ reg |= MACB_BIT(SPD);
- ncfgr = readl(macb->regs + MACB_NCFGR);
- ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
- if (speed)
- ncfgr |= MACB_BIT(SPD);
- if (duplex)
- ncfgr |= MACB_BIT(FD);
- writel(ncfgr, macb->regs + MACB_NCFGR);
+ writel(reg, macb->regs + MACB_NCFGR);
+}
- return 0;
+static int macb_open(struct eth_device *edev)
+{
+ struct macb_device *macb = edev->priv;
+
+ debug("%s\n", __func__);
+
+ /* Obtain the PHY's address/id */
+ return phy_device_connect(edev, &macb->miibus, macb->phy_addr,
+ macb_adjust_link, macb->phy_flags,
+ macb->interface);
}
static int macb_init(struct eth_device *edev)
@@ -264,7 +274,7 @@ static int macb_init(struct eth_device *edev)
writel((ulong)macb->rx_ring, macb->regs + MACB_RBQP);
writel((ulong)macb->tx_ring, macb->regs + MACB_TBQP);
- if (macb->flags & AT91SAM_ETHER_RMII)
+ if (macb->interface == PHY_INTERFACE_MODE_RMII)
val |= MACB_BIT(RMII);
else
val &= ~MACB_BIT(RMII);
@@ -298,10 +308,9 @@ static void macb_halt(struct eth_device *edev)
writel(MACB_BIT(CLRSTAT), macb->regs + MACB_NCR);
}
-static int macb_phy_read(struct mii_device *mdev, int addr, int reg)
+static int macb_phy_read(struct mii_bus *bus, int addr, int reg)
{
- struct eth_device *edev = mdev->edev;
- struct macb_device *macb = edev->priv;
+ struct macb_device *macb = bus->priv;
unsigned long netctl;
unsigned long netstat;
@@ -341,10 +350,9 @@ static int macb_phy_read(struct mii_device *mdev, int addr, int reg)
return value;
}
-static int macb_phy_write(struct mii_device *mdev, int addr, int reg, int value)
+static int macb_phy_write(struct mii_bus *bus, int addr, int reg, u16 value)
{
- struct eth_device *edev = mdev->edev;
- struct macb_device *macb = edev->priv;
+ struct macb_device *macb = bus->priv;
unsigned long netctl;
unsigned long netstat;
unsigned long frame;
@@ -425,14 +433,19 @@ static int macb_probe(struct device_d *dev)
edev->set_ethaddr = macb_set_ethaddr;
edev->parent = dev;
- macb->miidev.read = macb_phy_read;
- macb->miidev.write = macb_phy_write;
- macb->miidev.address = pdata->phy_addr;
- macb->miidev.flags = pdata->flags & AT91SAM_ETHER_FORCE_LINK ?
- MIIDEV_FORCE_LINK : 0;
- macb->miidev.edev = edev;
- macb->miidev.parent = dev;
- macb->flags = pdata->flags;
+ macb->miibus.read = macb_phy_read;
+ macb->miibus.write = macb_phy_write;
+ macb->phy_addr = pdata->phy_addr;
+ macb->miibus.priv = macb;
+ macb->miibus.parent = dev;
+
+ if (pdata->flags & AT91SAM_ETHER_RMII)
+ macb->interface = PHY_INTERFACE_MODE_RMII;
+ else
+ macb->interface = PHY_INTERFACE_MODE_MII;
+
+ macb->phy_flags = pdata->flags & AT91SAM_ETHER_FORCE_LINK ?
+ PHYLIB_FORCE_LINK : 0;
macb->rx_buffer = dma_alloc_coherent(CFG_MACB_RX_BUFFER_SIZE);
macb->rx_ring = dma_alloc_coherent(CFG_MACB_RX_RING_SIZE * sizeof(struct macb_dma_desc));
@@ -467,7 +480,7 @@ static int macb_probe(struct device_d *dev)
writel(ncfgr, macb->regs + MACB_NCFGR);
- mii_register(&macb->miidev);
+ mdiobus_register(&macb->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c
deleted file mode 100644
index 5d73ff5597..0000000000
--- a/drivers/net/miidev.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * miidev.c - generic phy abstraction
- *
- * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
- *
- * 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 version 2
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <common.h>
-#include <driver.h>
-#include <init.h>
-#include <miidev.h>
-#include <clock.h>
-#include <net.h>
-#include <malloc.h>
-
-static LIST_HEAD(miidev_list);
-
-int miidev_restart_aneg(struct mii_device *mdev)
-{
- int status, timeout;
- uint64_t start;
-
- status = mii_write(mdev, mdev->address, MII_BMCR, BMCR_RESET);
- if (status)
- return status;
-
- start = get_time_ns();
- do {
- status = mii_read(mdev, mdev->address, MII_BMCR);
- if (status < 0)
- return status;
-
- if (is_timeout(start, SECOND))
- return -ETIMEDOUT;
-
- } while (status & BMCR_RESET);
-
- if (mdev->flags & MIIDEV_FORCE_LINK)
- return 0;
-
- if (mdev->flags & MIIDEV_FORCE_10) {
- printf("Forcing 10 Mbps ethernet link... ");
-
- status = mii_read(mdev, mdev->address, MII_BMSR);
- if (status < 0)
- return status;
-
- status = mii_write(mdev, mdev->address, MII_BMCR, BMCR_FULLDPLX | BMCR_CTST);
- if (status)
- return status;
-
- timeout = 20;
- do { /* wait for link status to go down */
- udelay(10000);
- if ((timeout--) == 0) {
- debug("hmmm, should not have waited...");
- break;
- }
- status = mii_read(mdev, mdev->address, MII_BMSR);
- if (status < 0)
- return status;
- } while (status & BMSR_LSTATUS);
-
- } else { /* MII100 */
- /*
- * Set the auto-negotiation advertisement register bits
- */
- status = mii_read(mdev, mdev->address, MII_ADVERTISE);
- if (status < 0)
- return status;
-
- status |= ADVERTISE_ALL;
-
- status = mii_write(mdev, mdev->address, MII_ADVERTISE, status);
- if (status)
- return status;
-
- status = mii_write(mdev, mdev->address, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
- if (status)
- return status;
- }
-
- return 0;
-}
-
-int miidev_wait_aneg(struct mii_device *mdev)
-{
- int status;
- uint64_t start = get_time_ns();
-
- if (mdev->flags & MIIDEV_FORCE_LINK)
- return 0;
-
- do {
- status = mii_read(mdev, mdev->address, MII_BMSR);
- if (status < 0)
- return status;
-
- if (is_timeout(start, 5 * SECOND)) {
- printf("%s: Autonegotiation timeout\n", mdev->cdev.name);
- return -ETIMEDOUT;
- }
-
- } while (!(status & BMSR_ANEGCOMPLETE));
-
- return 0;
-}
-
-int miidev_get_status(struct mii_device *mdev)
-{
- int ret, status, adv, lpa;
-
- ret = mii_read(mdev, mdev->address, MII_BMSR);
- if (ret < 0)
- goto err_out;
-
- status = ret & BMSR_LSTATUS ? MIIDEV_STATUS_IS_UP : 0;
-
- if (ret & BMSR_ESTATEN) {
- ret = mii_read(mdev, mdev->address, MII_ESTATUS);
- if (ret < 0)
- goto err_out;
- if (ret & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF))
- mdev->capabilities = MIIDEV_CAPABLE_1000M;
- }
-
- ret = mii_read(mdev, mdev->address, MII_BMCR);
- if (ret < 0)
- goto err_out;
-
- if (ret & BMCR_ANENABLE) {
- if (mdev->capabilities & MIIDEV_CAPABLE_1000M) {
- lpa = mii_read(mdev, mdev->address, MII_STAT1000);
- if (lpa < 0)
- goto err_out;
- adv = mii_read(mdev, mdev->address, MII_CTRL1000);
- if (adv < 0)
- goto err_out;
- lpa &= adv << 2;
- if (lpa & (LPA_1000FULL | LPA_1000HALF)) {
- if (lpa & LPA_1000FULL)
- status |= MIIDEV_STATUS_IS_FULL_DUPLEX;
- status |= MIIDEV_STATUS_IS_1000MBIT;
- return status;
- }
- }
- lpa = mii_read(mdev, mdev->address, MII_LPA);
- if (lpa < 0)
- goto err_out;
- adv = mii_read(mdev, mdev->address, MII_ADVERTISE);
- if (adv < 0)
- goto err_out;
- lpa &= adv;
- status |= lpa & LPA_DUPLEX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0;
- status |= lpa & LPA_100 ? MIIDEV_STATUS_IS_100MBIT :
- MIIDEV_STATUS_IS_10MBIT;
- } else {
- status |= ret & BMCR_FULLDPLX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0;
- status |= ret & BMCR_SPEED100 ? MIIDEV_STATUS_IS_100MBIT :
- MIIDEV_STATUS_IS_10MBIT;
- }
-
- return status;
-err_out:
- printf("%s: failed to read (%d)\n", mdev->cdev.name, ret);
- return ret;
-}
-
-int miidev_print_status(struct mii_device *mdev)
-{
- char *duplex;
- int speed, status;
-
- if (mdev->flags & MIIDEV_FORCE_LINK) {
- printf("Forcing link present...\n");
- return 0;
- }
-
- status = miidev_get_status(mdev);
- if (status < 0)
- return status;
-
- duplex = status & MIIDEV_STATUS_IS_FULL_DUPLEX ? "Full" : "Half";
- speed = status & MIIDEV_STATUS_IS_1000MBIT ? 1000 :
- (status & MIIDEV_STATUS_IS_100MBIT ? 100 : 10);
-
- printf("%s: Link is %s", mdev->cdev.name,
- status & MIIDEV_STATUS_IS_UP ? "up" : "down");
- printf(" - %d/%s\n", speed, duplex);
-
- return 0;
-}
-
-static ssize_t miidev_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
-{
- int i = count;
- uint16_t *buf = _buf;
- struct mii_device *mdev = cdev->priv;
-
- while (i > 0) {
- *buf = mii_read(mdev, mdev->address, offset / 2);
- buf++;
- i -= 2;
- offset += 2;
- }
-
- return count;
-}
-
-static ssize_t miidev_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
-{
- int i = count;
- const uint16_t *buf = _buf;
- struct mii_device *mdev = cdev->priv;
-
- while (i > 0) {
- mii_write(mdev, mdev->address, offset / 2, *buf);
- buf++;
- i -= 2;
- offset += 2;
- }
-
- return count;
-}
-
-static struct file_operations miidev_ops = {
- .read = miidev_read,
- .write = miidev_write,
- .lseek = dev_lseek_default,
-};
-
-static int miidev_probe(struct device_d *dev)
-{
- struct mii_device *mdev = dev->priv;
-
- mdev->capabilities = 0;
- mdev->cdev.name = asprintf("phy%d", dev->id);
- mdev->cdev.size = 64;
- mdev->cdev.ops = &miidev_ops;
- mdev->cdev.priv = mdev;
- mdev->cdev.dev = dev;
- devfs_create(&mdev->cdev);
- list_add_tail(&mdev->list, &miidev_list);
- return 0;
-}
-
-static void miidev_remove(struct device_d *dev)
-{
- struct mii_device *mdev = dev->priv;
-
- list_del(&mdev->list);
-
- free(mdev->cdev.name);
- devfs_remove(&mdev->cdev);
-}
-
-struct mii_device *mii_open(const char *name)
-{
- struct mii_device *mdev;
-
- list_for_each_entry(mdev, &miidev_list, list) {
- if (!strcmp(name, mdev->cdev.name))
- return mdev;
- }
- return NULL;
-}
-
-void mii_close(struct mii_device *mdev)
-{
-}
-
-static struct driver_d miidev_drv = {
- .name = "miidev",
- .probe = miidev_probe,
- .remove = miidev_remove,
-};
-
-int mii_register(struct mii_device *mdev)
-{
- mdev->dev.priv = mdev;
- mdev->dev.id = DEVICE_ID_DYNAMIC;
- strcpy(mdev->dev.name, "miidev");
- if (mdev->parent)
- dev_add_child(mdev->parent, &mdev->dev);
-
- return register_device(&mdev->dev);
-}
-
-void mii_unregister(struct mii_device *mdev)
-{
- unregister_device(&mdev->dev);
-}
-
-static int miidev_init(void)
-{
- register_driver(&miidev_drv);
- return 0;
-}
-
-device_initcall(miidev_init);
-
diff --git a/drivers/net/netx_eth.c b/drivers/net/netx_eth.c
index 2d92a2e4dc..a4764258c1 100644
--- a/drivers/net/netx_eth.c
+++ b/drivers/net/netx_eth.c
@@ -2,13 +2,13 @@
#include <command.h>
#include <net.h>
#include <io.h>
-#include <miidev.h>
#include <mach/netx-xc.h>
#include <mach/netx-eth.h>
#include <mach/netx-regs.h>
#include <xfuncs.h>
#include <init.h>
#include <driver.h>
+#include <linux/phy.h>
#define ETH_MAC_LOCAL_CONFIG 0x1560
#define ETH_MAC_4321 0x1564
@@ -47,7 +47,7 @@
#define CON_FIFO_PORT_LO(xcno) (6 + ((xcno) << 3)) /* Index of the FIFO where sent Data packages are confirmed */
struct netx_eth_priv {
- struct mii_device miidev;
+ struct mii_bus miibus;
int xcno;
};
@@ -118,7 +118,7 @@ static int netx_eth_rx (struct eth_device *edev)
return 0;
}
-static int netx_miidev_read(struct mii_device *mdev, int phy_addr, int reg)
+static int netx_miibus_read(struct mii_bus *bus, int phy_addr, int reg)
{
int value;
@@ -135,8 +135,8 @@ static int netx_miidev_read(struct mii_device *mdev, int phy_addr, int reg)
return value;
}
-static int netx_miidev_write(struct mii_device *mdev, int phy_addr,
- int reg, int val)
+static int netx_miibus_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 val)
{
debug("%s: addr: 0x%02x reg: 0x%02x val: 0x%04x\n",__func__,
phy_addr, reg, val);
@@ -189,13 +189,15 @@ static int netx_eth_init_dev(struct eth_device *edev)
for (i = 2; i <= 18; i++)
PFIFO_REG( PFIFO_BASE(EMPTY_PTR_FIFO(xcno)) ) = FIFO_PTR_FRAMENO(i) | FIFO_PTR_SEGMENT(xcno);
- miidev_restart_aneg(&priv->miidev);
return 0;
}
static int netx_eth_open(struct eth_device *edev)
{
- return 0;
+ struct netx_eth_priv *priv = (struct netx_eth_priv *)edev->priv;
+
+ return phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static void netx_eth_halt (struct eth_device *edev)
@@ -259,14 +261,12 @@ static int netx_eth_probe(struct device_d *dev)
edev->set_ethaddr = netx_eth_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = netx_miidev_read;
- priv->miidev.write = netx_miidev_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.parent = dev;
+ priv->miibus.read = netx_miibus_read;
+ priv->miibus.write = netx_miibus_write;
+ priv->miibus.parent = dev;
netx_eth_init_phy();
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
new file mode 100644
index 0000000000..b66261ae99
--- /dev/null
+++ b/drivers/net/phy/Kconfig
@@ -0,0 +1,17 @@
+#
+# PHY Layer Configuration
+#
+
+menu "phylib "
+
+if PHYLIB
+
+comment "MII PHY device drivers"
+
+config GENERIC_PHY
+ bool "Drivers for the Generic PHYs"
+ default y
+
+endif
+
+endmenu
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
new file mode 100644
index 0000000000..82e90d426a
--- /dev/null
+++ b/drivers/net/phy/Makefile
@@ -0,0 +1,2 @@
+obj-y += phy.o mdio_bus.o
+obj-$(CONFIG_GENERIC_PHY) += generic.o
diff --git a/drivers/net/phy/generic.c b/drivers/net/phy/generic.c
new file mode 100644
index 0000000000..3f5f127065
--- /dev/null
+++ b/drivers/net/phy/generic.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * 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 <linux/phy.h>
+#include <init.h>
+
+static struct phy_driver generic_phy = {
+ .drv.name = "Generic PHY",
+ .phy_id = PHY_ANY_UID,
+ .phy_id_mask = PHY_ANY_UID,
+ .features = 0,
+};
+
+static int generic_phy_register(void)
+{
+ return phy_driver_register(&generic_phy);
+}
+device_initcall(generic_phy_register);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
new file mode 100644
index 0000000000..93d6fe15e1
--- /dev/null
+++ b/drivers/net/phy/mdio_bus.c
@@ -0,0 +1,250 @@
+/*
+ * drivers/net/phy/mdio_bus.c
+ *
+ * MDIO Bus interface
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <clock.h>
+#include <net.h>
+#include <errno.h>
+#include <linux/phy.h>
+#include <linux/err.h>
+
+/**
+ * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus
+ * @bus: target mii_bus
+ *
+ * Description: Called by a bus driver to bring up all the PHYs
+ * on a given bus, and attach them to the bus.
+ *
+ * Returns 0 on success or < 0 on error.
+ */
+int mdiobus_register(struct mii_bus *bus)
+{
+ int i, err;
+
+ if (NULL == bus ||
+ NULL == bus->read ||
+ NULL == bus->write)
+ return -EINVAL;
+
+ bus->dev.priv = bus;
+ bus->dev.id = DEVICE_ID_DYNAMIC;
+ strcpy(bus->dev.name, "miibus");
+ bus->dev.parent = bus->parent;
+ if (bus->parent)
+ dev_add_child(bus->parent, &bus->dev);
+
+ err = register_device(&bus->dev);
+ if (err) {
+ pr_err("mii_bus %s failed to register\n", bus->dev.name);
+ return -EINVAL;
+ }
+
+ if (bus->reset)
+ bus->reset(bus);
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ if ((bus->phy_mask & (1 << i)) == 0) {
+ struct phy_device *phydev;
+
+ phydev = mdiobus_scan(bus, i);
+ if (IS_ERR(phydev)) {
+ err = PTR_ERR(phydev);
+ goto error;
+ }
+ }
+ }
+
+ pr_info("%s: probed\n", dev_name(&bus->dev));
+ return 0;
+
+error:
+ while (--i >= 0) {
+ if (bus->phy_map[i]) {
+ kfree(bus->phy_map[i]);
+ bus->phy_map[i] = NULL;
+ }
+ }
+ return err;
+}
+EXPORT_SYMBOL(mdiobus_register);
+
+void mdiobus_unregister(struct mii_bus *bus)
+{
+ int i;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ if (bus->phy_map[i])
+ unregister_device(&bus->phy_map[i]->dev);
+ bus->phy_map[i] = NULL;
+ }
+}
+EXPORT_SYMBOL(mdiobus_unregister);
+
+struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
+{
+ struct phy_device *phydev;
+
+ phydev = get_phy_device(bus, addr);
+ if (IS_ERR(phydev) || phydev == NULL)
+ return phydev;
+
+ bus->phy_map[addr] = phydev;
+
+ return phydev;
+}
+EXPORT_SYMBOL(mdiobus_scan);
+
+/**
+ * mdio_bus_match - determine if given PHY driver supports the given PHY device
+ * @dev: target PHY device
+ * @drv: given PHY driver
+ *
+ * Description: Given a PHY device, and a PHY driver, return 1 if
+ * the driver supports the device. Otherwise, return 0.
+ */
+static int mdio_bus_match(struct device_d *dev, struct driver_d *drv)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct phy_driver *phydrv = to_phy_driver(drv);
+
+ return ((phydrv->phy_id & phydrv->phy_id_mask) ==
+ (phydev->phy_id & phydrv->phy_id_mask));
+}
+
+static ssize_t phydev_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i = count;
+ uint16_t *buf = _buf;
+ struct phy_device *phydev = cdev->priv;
+
+ while (i > 0) {
+ *buf = phy_read(phydev, offset / 2);
+ buf++;
+ i -= 2;
+ offset += 2;
+ }
+
+ return count;
+}
+
+static ssize_t phydev_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
+{
+ int i = count;
+ const uint16_t *buf = _buf;
+ struct phy_device *phydev = cdev->priv;
+
+ while (i > 0) {
+ phy_write(phydev, offset / 2, *buf);
+ buf++;
+ i -= 2;
+ offset += 2;
+ }
+
+ return count;
+}
+
+static struct file_operations phydev_ops = {
+ .read = phydev_read,
+ .write = phydev_write,
+ .lseek = dev_lseek_default,
+};
+
+static int mdio_bus_probe(struct device_d *_dev)
+{
+ struct phy_device *dev = to_phy_device(_dev);
+ struct phy_driver *drv = to_phy_driver(_dev->driver);
+
+ char str[16];
+
+ dev->attached_dev->phydev = dev;
+ dev->dev.parent = &dev->attached_dev->dev;
+ dev_add_child(dev->dev.parent, _dev);
+
+ if (drv->probe) {
+ int ret;
+
+ ret = drv->probe(dev);
+ if (ret) {
+ dev->attached_dev->phydev = NULL;
+ dev->attached_dev = NULL;
+ return ret;
+ }
+ }
+
+ if (dev->dev_flags) {
+ if (dev->dev_flags & PHYLIB_FORCE_10) {
+ dev->speed = SPEED_10;
+ dev->duplex = DUPLEX_FULL;
+ dev->autoneg = !AUTONEG_ENABLE;
+ }
+ }
+
+ /* Start out supporting everything. Eventually,
+ * a controller will attach, and may modify one
+ * or both of these values */
+ dev->supported = drv->features;
+ dev->advertising = drv->features;
+
+ drv->config_init(dev);
+
+ /* Sanitize settings based on PHY capabilities */
+ if ((dev->supported & SUPPORTED_Autoneg) == 0)
+ dev->autoneg = AUTONEG_DISABLE;
+
+ sprintf(str, "%d", dev->addr);
+ dev_add_param_fixed(&dev->dev, "phy_addr", str);
+
+ dev->cdev.name = asprintf("phy%d", _dev->id);
+ dev->cdev.size = 64;
+ dev->cdev.ops = &phydev_ops;
+ dev->cdev.priv = dev;
+ dev->cdev.dev = _dev;
+ devfs_create(&dev->cdev);
+
+ return 0;
+}
+
+static void mdio_bus_remove(struct device_d *_dev)
+{
+ struct phy_device *dev = to_phy_device(_dev);
+ struct phy_driver *drv = to_phy_driver(_dev->driver);
+
+ if (drv->remove)
+ drv->remove(dev);
+
+ free(dev->cdev.name);
+ devfs_remove(&dev->cdev);
+}
+
+struct bus_type mdio_bus_type = {
+ .name = "mdio_bus",
+ .match = mdio_bus_match,
+ .probe = mdio_bus_probe,
+ .remove = mdio_bus_remove,
+};
+EXPORT_SYMBOL(mdio_bus_type);
+
+#if 0
+static int mdio_bus_init(void)
+{
+ return bus_register(&mdio_bus_type);
+}
+pure_initcall(mdio_bus_init);
+#endif
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
new file mode 100644
index 0000000000..88c3ff7723
--- /dev/null
+++ b/drivers/net/phy/phy.c
@@ -0,0 +1,583 @@
+/*
+ * drivers/net/phy/phy.c
+ *
+ * Framework for finding and configuring PHYs.
+ * Also contains generic PHY driver
+ *
+ * Copyright (c) 2009-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * 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 <common.h>
+#include <driver.h>
+#include <net.h>
+#include <malloc.h>
+#include <linux/phy.h>
+#include <linux/phy.h>
+#include <linux/err.h>
+
+#define PHY_AN_TIMEOUT 10
+
+static int genphy_config_init(struct phy_device *phydev);
+
+int phy_update_status(struct phy_device *dev)
+{
+ struct phy_driver *drv = to_phy_driver(dev->dev.driver);
+ struct eth_device *edev = dev->attached_dev;
+ int ret;
+ int oldspeed = dev->speed, oldduplex = dev->duplex;
+
+ ret = drv->read_status(dev);
+ if (ret)
+ return ret;
+
+ if (dev->speed == oldspeed && dev->duplex == oldduplex)
+ return 0;
+
+ if (dev->adjust_link)
+ dev->adjust_link(edev);
+
+ if (dev->link)
+ printf("%dMbps %s duplex link detected\n", dev->speed,
+ dev->duplex ? "full" : "half");
+
+ return 0;
+}
+
+struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id)
+{
+ struct phy_device *dev;
+
+ /* We allocate the device, and initialize the
+ * default values */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+ if (NULL == dev)
+ return (struct phy_device*) PTR_ERR((void*)-ENOMEM);
+
+ dev->speed = 0;
+ dev->duplex = -1;
+ dev->pause = dev->asym_pause = 0;
+ dev->link = 1;
+ dev->autoneg = AUTONEG_ENABLE;
+
+ dev->addr = addr;
+ dev->phy_id = phy_id;
+
+ dev->bus = bus;
+ dev->dev.parent = bus->parent;
+ dev->dev.bus = &mdio_bus_type;
+
+ strcpy(dev->dev.name, "phy");
+ dev->dev.id = DEVICE_ID_DYNAMIC;
+
+ return dev;
+}
+/**
+ * get_phy_id - reads the specified addr for its ID.
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ * @phy_id: where to store the ID retrieved.
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, stores it in @phy_id and returns zero on success.
+ */
+int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id)
+{
+ int phy_reg;
+
+ /* Grab the bits from PHYIR1, and put them
+ * in the upper half */
+ phy_reg = mdiobus_read(bus, addr, MII_PHYSID1);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id = (phy_reg & 0xffff) << 16;
+
+ /* Grab the bits from PHYIR2, and put them in the lower half */
+ phy_reg = mdiobus_read(bus, addr, MII_PHYSID2);
+
+ if (phy_reg < 0)
+ return -EIO;
+
+ *phy_id |= (phy_reg & 0xffff);
+
+ return 0;
+}
+
+/**
+ * get_phy_device - reads the specified PHY device and returns its @phy_device struct
+ * @bus: the target MII bus
+ * @addr: PHY address on the MII bus
+ *
+ * Description: Reads the ID registers of the PHY at @addr on the
+ * @bus, then allocates and returns the phy_device to represent it.
+ */
+struct phy_device *get_phy_device(struct mii_bus *bus, int addr)
+{
+ struct phy_device *dev = NULL;
+ u32 phy_id = 0;
+ int r;
+
+ r = get_phy_id(bus, addr, &phy_id);
+ if (r)
+ return ERR_PTR(r);
+
+ /* If the phy_id is mostly Fs, there is no device there */
+ if ((phy_id & 0x1fffffff) == 0x1fffffff)
+ return NULL;
+
+ dev = phy_device_create(bus, addr, phy_id);
+
+ return dev;
+}
+
+/* Automatically gets and returns the PHY device */
+int phy_device_connect(struct eth_device *edev, struct mii_bus *bus, int addr,
+ void (*adjust_link) (struct eth_device *edev),
+ u32 flags, phy_interface_t interface)
+{
+ struct phy_driver* drv;
+ struct phy_device* dev = NULL;
+ unsigned int i;
+ int ret = -EINVAL;
+
+ if (!edev->phydev) {
+ if (addr >= 0) {
+ dev = bus->phy_map[addr];
+ if (!dev) {
+ ret = -EIO;
+ goto fail;
+ }
+
+ dev->attached_dev = edev;
+ dev->interface = interface;
+ dev->dev_flags = flags;
+
+ ret = register_device(&dev->dev);
+ if (ret)
+ goto fail;
+ } else {
+ for (i = 0; i < PHY_MAX_ADDR && !edev->phydev; i++) {
+ dev = bus->phy_map[i];
+ if (!dev || dev->attached_dev)
+ continue;
+
+ dev->attached_dev = edev;
+ dev->interface = interface;
+ dev->dev_flags = flags;
+
+ ret = register_device(&dev->dev);
+ if (ret)
+ goto fail;
+
+ break;
+ }
+ }
+
+ if (!edev->phydev) {
+ ret = -EIO;
+ goto fail;
+ }
+ }
+
+ dev = edev->phydev;
+ drv = to_phy_driver(dev->dev.driver);
+
+ drv->config_aneg(dev);
+
+ dev->adjust_link = adjust_link;
+
+ return 0;
+
+fail:
+ if (dev)
+ dev->attached_dev = NULL;
+ puts("Unable to find a PHY (unknown ID?)\n");
+ return ret;
+}
+
+/* Generic PHY support and helper functions */
+
+/**
+ * genphy_config_advert - sanitize and advertise auto-negotiation parameters
+ * @phydev: target phy_device struct
+ *
+ * Description: Writes MII_ADVERTISE with the appropriate values,
+ * after sanitizing the values to make sure we only advertise
+ * what is supported. Returns < 0 on error, 0 if the PHY's advertisement
+ * hasn't changed, and > 0 if it has changed.
+ */
+int genphy_config_advert(struct phy_device *phydev)
+{
+ u32 advertise;
+ int oldadv, adv;
+ int err, changed = 0;
+
+ /* Only allow advertising what
+ * this PHY supports */
+ phydev->advertising &= phydev->supported;
+ advertise = phydev->advertising;
+
+ /* Setup standard advertisement */
+ oldadv = adv = phy_read(phydev, MII_ADVERTISE);
+
+ if (adv < 0)
+ return adv;
+
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+ adv |= ethtool_adv_to_mii_adv_t(advertise);
+
+ if (adv != oldadv) {
+ err = phy_write(phydev, MII_ADVERTISE, adv);
+
+ if (err < 0)
+ return err;
+ changed = 1;
+ }
+
+ /* Configure gigabit if it's supported */
+ if (phydev->supported & (SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full)) {
+ oldadv = adv = phy_read(phydev, MII_CTRL1000);
+
+ if (adv < 0)
+ return adv;
+
+ adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ adv |= ethtool_adv_to_mii_ctrl1000_t(advertise);
+
+ if (adv != oldadv) {
+ err = phy_write(phydev, MII_CTRL1000, adv);
+
+ if (err < 0)
+ return err;
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+/**
+ * genphy_setup_forced - configures/forces speed/duplex from @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Configures MII_BMCR to force speed/duplex
+ * to the values in phydev. Assumes that the values are valid.
+ * Please see phy_sanitize_settings().
+ */
+int genphy_setup_forced(struct phy_device *phydev)
+{
+ int err;
+ int ctl = 0;
+
+ phydev->pause = phydev->asym_pause = 0;
+
+ if (SPEED_1000 == phydev->speed)
+ ctl |= BMCR_SPEED1000;
+ else if (SPEED_100 == phydev->speed)
+ ctl |= BMCR_SPEED100;
+
+ if (DUPLEX_FULL == phydev->duplex)
+ ctl |= BMCR_FULLDPLX;
+
+ err = phy_write(phydev, MII_BMCR, ctl);
+
+ return err;
+}
+
+static int phy_aneg_done(struct phy_device *phydev)
+{
+ uint64_t start = get_time_ns();
+ int ctl;
+
+ while (!is_timeout(start, PHY_AN_TIMEOUT * SECOND)) {
+ ctl = phy_read(phydev, MII_BMSR);
+ if (ctl & BMSR_ANEGCOMPLETE) {
+ phydev->link = 1;
+ return 0;
+ }
+
+ /* Restart auto-negotiation if remote fault */
+ if (ctl & BMSR_RFAULT) {
+ puts("PHY remote fault detected\n"
+ "PHY restarting auto-negotiation\n");
+ phy_write(phydev, MII_BMCR,
+ BMCR_ANENABLE | BMCR_ANRESTART);
+ }
+ }
+
+ phydev->link = 0;
+ return -ETIMEDOUT;
+}
+
+/**
+ * genphy_restart_aneg - Enable and Restart Autonegotiation
+ * @phydev: target phy_device struct
+ */
+int genphy_restart_aneg(struct phy_device *phydev)
+{
+ int ctl;
+
+ ctl = phy_read(phydev, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+
+ /* Don't isolate the PHY if we're negotiating */
+ ctl &= ~(BMCR_ISOLATE);
+
+ ctl = phy_write(phydev, MII_BMCR, ctl);
+
+ if (ctl < 0)
+ return ctl;
+
+ return phy_aneg_done(phydev);
+}
+
+/**
+ * genphy_config_aneg - restart auto-negotiation or write BMCR
+ * @phydev: target phy_device struct
+ *
+ * Description: If auto-negotiation is enabled, we configure the
+ * advertising, and then restart auto-negotiation. If it is not
+ * enabled, then we write the BMCR.
+ */
+int genphy_config_aneg(struct phy_device *phydev)
+{
+ int result;
+
+ if (AUTONEG_ENABLE != phydev->autoneg)
+ return genphy_setup_forced(phydev);
+
+ result = genphy_config_advert(phydev);
+
+ if (result < 0) /* error */
+ return result;
+
+ if (result == 0) {
+ /* Advertisement hasn't changed, but maybe aneg was never on to
+ * begin with? Or maybe phy was isolated? */
+ int ctl = phy_read(phydev, MII_BMCR);
+
+ if (ctl < 0)
+ return ctl;
+
+ if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
+ result = 1; /* do restart aneg */
+ }
+
+ /* Only restart aneg if we are advertising something different
+ * than we were before. */
+ if (result > 0)
+ result = genphy_restart_aneg(phydev);
+
+ return result;
+}
+
+/**
+ * genphy_update_link - update link status in @phydev
+ * @phydev: target phy_device struct
+ *
+ * Description: Update the value in phydev->link to reflect the
+ * current link value. In order to do this, we need to read
+ * the status register twice, keeping the second value.
+ */
+int genphy_update_link(struct phy_device *phydev)
+{
+ int status;
+
+ /* Do a fake read */
+ status = phy_read(phydev, MII_BMSR);
+
+ if (status < 0)
+ return status;
+
+ /* wait phy status update in the phy */
+ udelay(1000);
+
+ /* Read link and autonegotiation status */
+ status = phy_read(phydev, MII_BMSR);
+
+ if (status < 0)
+ return status;
+
+ if ((status & BMSR_LSTATUS) == 0)
+ phydev->link = 0;
+ else
+ phydev->link = 1;
+
+ return 0;
+}
+
+/**
+ * genphy_read_status - check the link status and update current link state
+ * @phydev: target phy_device struct
+ *
+ * Description: Check the link, then figure out the current state
+ * by comparing what we advertise with what the link partner
+ * advertises. Start by checking the gigabit possibilities,
+ * then move on to 10/100.
+ */
+int genphy_read_status(struct phy_device *phydev)
+{
+ int adv;
+ int err;
+ int lpa;
+ int lpagb = 0;
+
+ /* Update the link, but return if there
+ * was an error */
+ err = genphy_update_link(phydev);
+ if (err)
+ return err;
+
+ if (AUTONEG_ENABLE == phydev->autoneg) {
+ if (phydev->supported & (SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full)) {
+ lpagb = phy_read(phydev, MII_STAT1000);
+
+ if (lpagb < 0)
+ return lpagb;
+
+ adv = phy_read(phydev, MII_CTRL1000);
+
+ if (adv < 0)
+ return adv;
+
+ lpagb &= adv << 2;
+ }
+
+ lpa = phy_read(phydev, MII_LPA);
+
+ if (lpa < 0)
+ return lpa;
+
+ adv = phy_read(phydev, MII_ADVERTISE);
+
+ if (adv < 0)
+ return adv;
+
+ lpa &= adv;
+
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+ phydev->pause = phydev->asym_pause = 0;
+
+ if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+ phydev->speed = SPEED_1000;
+
+ if (lpagb & LPA_1000FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ phydev->speed = SPEED_100;
+
+ if (lpa & LPA_100FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else
+ if (lpa & LPA_10FULL)
+ phydev->duplex = DUPLEX_FULL;
+
+ if (phydev->duplex == DUPLEX_FULL) {
+ phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+ phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+ }
+ } else {
+ int bmcr = phy_read(phydev, MII_BMCR);
+ if (bmcr < 0)
+ return bmcr;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ if (bmcr & BMCR_SPEED1000)
+ phydev->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_10;
+
+ phydev->pause = phydev->asym_pause = 0;
+ }
+
+ return 0;
+}
+
+static int genphy_config_init(struct phy_device *phydev)
+{
+ int val;
+ u32 features;
+
+ /* For now, I'll claim that the generic driver supports
+ * all possible port types */
+ features = (SUPPORTED_TP | SUPPORTED_MII
+ | SUPPORTED_AUI | SUPPORTED_FIBRE |
+ SUPPORTED_BNC);
+
+ /* Do we support autonegotiation? */
+ val = phy_read(phydev, MII_BMSR);
+
+ if (val < 0)
+ return val;
+
+ if (val & BMSR_ANEGCAPABLE)
+ features |= SUPPORTED_Autoneg;
+
+ if (val & BMSR_100FULL)
+ features |= SUPPORTED_100baseT_Full;
+ if (val & BMSR_100HALF)
+ features |= SUPPORTED_100baseT_Half;
+ if (val & BMSR_10FULL)
+ features |= SUPPORTED_10baseT_Full;
+ if (val & BMSR_10HALF)
+ features |= SUPPORTED_10baseT_Half;
+
+ if (val & BMSR_ESTATEN) {
+ val = phy_read(phydev, MII_ESTATUS);
+
+ if (val < 0)
+ return val;
+
+ if (val & ESTATUS_1000_TFULL)
+ features |= SUPPORTED_1000baseT_Full;
+ if (val & ESTATUS_1000_THALF)
+ features |= SUPPORTED_1000baseT_Half;
+ }
+
+ phydev->supported = features;
+ phydev->advertising = features;
+
+ return 0;
+}
+
+int phy_driver_register(struct phy_driver *phydrv)
+{
+ phydrv->drv.bus = &mdio_bus_type;
+
+ if (!phydrv->config_init)
+ phydrv->config_init = genphy_config_init;
+
+ if (!phydrv->config_aneg)
+ phydrv->config_aneg = genphy_config_aneg;
+
+ if (!phydrv->read_status)
+ phydrv->read_status = genphy_read_status;
+
+ return register_driver(&phydrv->drv);
+}
diff --git a/drivers/net/smc91111.c b/drivers/net/smc91111.c
index 66ca9bca19..1f5a43191a 100644
--- a/drivers/net/smc91111.c
+++ b/drivers/net/smc91111.c
@@ -63,13 +63,13 @@
#include <command.h>
#include <net.h>
-#include <miidev.h>
#include <malloc.h>
#include <init.h>
#include <xfuncs.h>
#include <errno.h>
#include <clock.h>
#include <io.h>
+#include <linux/phy.h>
/*---------------------------------------------------------------
.
@@ -447,7 +447,7 @@ struct accessors {
};
struct smc91c111_priv {
- struct mii_device miidev;
+ struct mii_bus miibus;
struct accessors a;
void __iomem *base;
};
@@ -617,11 +617,10 @@ static void smc_wait_mmu_release_complete(struct smc91c111_priv *priv)
}
}
-static int smc91c111_phy_write(struct mii_device *mdev, int phyaddr,
- int phyreg, int phydata)
+static int smc91c111_phy_write(struct mii_bus *bus, int phyaddr,
+ int phyreg, u16 phydata)
{
- struct eth_device *edev = mdev->edev;
- struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
+ struct smc91c111_priv *priv = (struct smc91c111_priv *)bus->priv;
int oldBank;
int i;
unsigned mask;
@@ -719,10 +718,9 @@ static int smc91c111_phy_write(struct mii_device *mdev, int phyaddr,
return 0;
}
-static int smc91c111_phy_read(struct mii_device *mdev, int phyaddr, int phyreg)
+static int smc91c111_phy_read(struct mii_bus *bus, int phyaddr, int phyreg)
{
- struct eth_device *edev = mdev->edev;
- struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
+ struct smc91c111_priv *priv = (struct smc91c111_priv *)bus->priv;
int oldBank;
int i;
unsigned char mask;
@@ -888,12 +886,15 @@ static void smc91c111_enable(struct eth_device *edev)
static int smc91c111_eth_open(struct eth_device *edev)
{
struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
- smc91c111_enable(edev);
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
+ /* Configure the Receive/Phy Control register */
+ SMC_SELECT_BANK(priv, 0);
+ SMC_outw(priv, RPC_DEFAULT, RPC_REG);
- return 0;
+ smc91c111_enable(edev);
+
+ return phy_device_connect(edev, &priv->miibus, 0, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static int smc91c111_eth_send(struct eth_device *edev, void *packet,
@@ -1275,14 +1276,6 @@ static void print_packet( unsigned char * buf, int length )
static int smc91c111_init_dev(struct eth_device *edev)
{
- struct smc91c111_priv *priv = (struct smc91c111_priv *)edev->priv;
-
- /* Configure the Receive/Phy Control register */
- SMC_SELECT_BANK(priv, 0);
- SMC_outw(priv, RPC_DEFAULT, RPC_REG);
-
- miidev_restart_aneg(&priv->miidev);
-
return 0;
}
@@ -1308,17 +1301,15 @@ static int smc91c111_probe(struct device_d *dev)
edev->set_ethaddr = smc91c111_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = smc91c111_phy_read;
- priv->miidev.write = smc91c111_phy_write;
- priv->miidev.address = 0;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = smc91c111_phy_read;
+ priv->miibus.write = smc91c111_phy_write;
+ priv->miibus.priv = priv;
+ priv->miibus.parent = dev;
priv->base = dev_request_mem_region(dev, 0);
smc91c111_reset(edev);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 9dc857ea97..8df6980363 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -26,7 +26,6 @@
#include <command.h>
#include <net.h>
-#include <miidev.h>
#include <malloc.h>
#include <init.h>
#include <xfuncs.h>
@@ -34,12 +33,13 @@
#include <clock.h>
#include <io.h>
#include <smc911x.h>
+#include <linux/phy.h>
#include "smc911x.h"
struct smc911x_priv {
struct eth_device edev;
- struct mii_device miidev;
+ struct mii_bus miibus;
void __iomem *base;
int shift;
@@ -194,9 +194,9 @@ static int smc911x_set_ethaddr(struct eth_device *edev, unsigned char *m)
return 0;
}
-static int smc911x_phy_read(struct mii_device *mdev, int phy_addr, int reg)
+static int smc911x_phy_read(struct mii_bus *bus, int phy_addr, int reg)
{
- struct eth_device *edev = mdev->edev;
+ struct eth_device *edev = bus->priv;
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
@@ -208,10 +208,10 @@ static int smc911x_phy_read(struct mii_device *mdev, int phy_addr, int reg)
return smc911x_get_mac_csr(edev, MII_DATA);
}
-static int smc911x_phy_write(struct mii_device *mdev, int phy_addr,
- int reg, int val)
+static int smc911x_phy_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 val)
{
- struct eth_device *edev = mdev->edev;
+ struct eth_device *edev = bus->priv;
while (smc911x_get_mac_csr(edev, MII_ACC) & MII_ACC_MII_BUSY);
@@ -304,9 +304,12 @@ static void smc911x_enable(struct eth_device *edev)
static int smc911x_eth_open(struct eth_device *edev)
{
struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
+ int ret;
- miidev_wait_aneg(&priv->miidev);
- miidev_print_status(&priv->miidev);
+ ret = phy_device_connect(edev, &priv->miibus, 1, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
+ if (ret)
+ return ret;
/* Turn on Tx + Rx */
smc911x_enable(edev);
@@ -401,13 +404,9 @@ static int smc911x_eth_rx(struct eth_device *edev)
static int smc911x_init_dev(struct eth_device *edev)
{
- struct smc911x_priv *priv = (struct smc911x_priv *)edev->priv;
-
smc911x_set_mac_csr(edev, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
MAC_CR_HBDIS);
- miidev_restart_aneg(&priv->miidev);
-
return 0;
}
@@ -532,17 +531,15 @@ static int smc911x_probe(struct device_d *dev)
edev->set_ethaddr = smc911x_set_ethaddr;
edev->parent = dev;
- priv->miidev.read = smc911x_phy_read;
- priv->miidev.write = smc911x_phy_write;
- priv->miidev.address = 1;
- priv->miidev.flags = 0;
- priv->miidev.edev = edev;
- priv->miidev.parent = dev;
+ priv->miibus.read = smc911x_phy_read;
+ priv->miibus.write = smc911x_phy_write;
+ priv->miibus.priv = edev;
+ priv->miibus.parent = dev;
smc911x_reset(edev);
smc911x_phy_reset(edev);
- mii_register(&priv->miidev);
+ mdiobus_register(&priv->miibus);
eth_register(edev);
return 0;
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 5c3a1e3f1c..d5c7031982 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -76,7 +76,7 @@ int tap_probe(struct device_d *dev)
struct tap_priv *priv;
int ret = 0;
- priv = xmalloc(sizeof(struct tap_priv));
+ priv = xzalloc(sizeof(struct tap_priv));
priv->name = "barebox";
priv->fd = tap_alloc(priv->name);
@@ -85,7 +85,7 @@ int tap_probe(struct device_d *dev)
goto out;
}
- edev = xmalloc(sizeof(struct eth_device));
+ edev = xzalloc(sizeof(struct eth_device));
edev->priv = priv;
edev->parent = dev;
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index b53dcc7c46..adb1b0b097 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -5,11 +5,11 @@ menuconfig NET_USB
if NET_USB
config NET_USB_ASIX
- select MIIDEV
+ select PHYLIB
bool "Asix compatible"
config NET_USB_SMSC95XX
- select MIIDEV
+ select PHYLIB
bool "SMSC95xx"
endif
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index be5a170d71..97680cfb54 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1,7 +1,7 @@
#include <common.h>
#include <init.h>
#include <net.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include <usb/usb.h>
#include <usb/usbnet.h>
#include <errno.h>
@@ -231,10 +231,9 @@ static inline int asix_set_hw_mii(struct usbnet *dev)
return ret;
}
-static int asix_mdio_read(struct mii_device *mdev, int phy_id, int loc)
+static int asix_mdio_read(struct mii_bus *bus, int phy_id, int loc)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
__le16 res;
asix_set_sw_mii(dev);
@@ -248,10 +247,9 @@ static int asix_mdio_read(struct mii_device *mdev, int phy_id, int loc)
return le16_to_cpu(res);
}
-static int asix_mdio_write(struct mii_device *mdev, int phy_id, int loc, int val)
+static int asix_mdio_write(struct mii_bus *bus, int phy_id, int loc, u16 val)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
__le16 res = cpu_to_le16(val);
dev_dbg(&dev->edev.dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x",
@@ -469,14 +467,13 @@ static int asix_tx_fixup(struct usbnet *dev,
static int asix_init_mii(struct usbnet *dev)
{
- dev->miidev.read = asix_mdio_read;
- dev->miidev.write = asix_mdio_write;
- dev->miidev.address = asix_get_phy_addr(dev);
- dev->miidev.flags = 0;
- dev->miidev.edev = &dev->edev;
- dev->miidev.parent = &dev->udev->dev;
-
- return mii_register(&dev->miidev);
+ dev->miibus.read = asix_mdio_read;
+ dev->miibus.write = asix_mdio_write;
+ dev->phy_addr = asix_get_phy_addr(dev);
+ dev->miibus.priv = dev;
+ dev->miibus.parent = &dev->udev->dev;
+
+ return mdiobus_register(&dev->miibus);
}
static int ax88172_link_reset(struct usbnet *dev)
@@ -631,7 +628,7 @@ out:
static void asix_unbind(struct usbnet *dev)
{
- mii_unregister(&dev->miidev);
+ mdiobus_unregister(&dev->miibus);
}
static struct driver_info ax8817x_info = {
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index d28a0dfe2b..38ca12f257 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -23,7 +23,7 @@
#include <malloc.h>
#include <asm/byteorder.h>
#include <errno.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include "smsc95xx.h"
#define SMSC_CHIPNAME "smsc95xx"
@@ -119,10 +119,9 @@ static int smsc95xx_phy_wait_not_busy(struct usbnet *dev)
return -EIO;
}
-static int smsc95xx_mdio_read(struct mii_device *mdev, int phy_id, int idx)
+static int smsc95xx_mdio_read(struct mii_bus *bus, int phy_id, int idx)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
u32 val, addr;
/* confirm MII not busy */
@@ -145,11 +144,10 @@ static int smsc95xx_mdio_read(struct mii_device *mdev, int phy_id, int idx)
return val & 0xffff;
}
-static int smsc95xx_mdio_write(struct mii_device *mdev, int phy_id, int idx,
- int regval)
+static int smsc95xx_mdio_write(struct mii_bus *bus, int phy_id, int idx,
+ u16 regval)
{
- struct eth_device *eth = mdev->edev;
- struct usbnet *dev = eth->priv;
+ struct usbnet *dev = bus->priv;
u32 val, addr;
/* confirm MII not busy */
@@ -435,20 +433,19 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
uint16_t val, bmcr;
/* Initialize MII structure */
- dev->miidev.read = smsc95xx_mdio_read;
- dev->miidev.write = smsc95xx_mdio_write;
- dev->miidev.address = 1; /* FIXME: asix_get_phy_addr(dev); */
- dev->miidev.flags = 0;
- dev->miidev.edev = &dev->edev;
- dev->miidev.parent = &dev->udev->dev;
-// dev->miidev.name = dev->edev.name;
+ dev->miibus.read = smsc95xx_mdio_read;
+ dev->miibus.write = smsc95xx_mdio_write;
+ dev->phy_addr = 1; /* FIXME: asix_get_phy_addr(dev); */
+ dev->miibus.priv = dev;
+ dev->miibus.parent = &dev->udev->dev;
+// dev->miibus.name = dev->edev.name;
/* reset phy and wait for reset to complete */
- smsc95xx_mdio_write(&dev->miidev, phy_id, MII_BMCR, BMCR_RESET);
+ smsc95xx_mdio_write(&dev->miibus, phy_id, MII_BMCR, BMCR_RESET);
do {
udelay(10 * 1000);
- bmcr = smsc95xx_mdio_read(&dev->miidev, phy_id, MII_BMCR);
+ bmcr = smsc95xx_mdio_read(&dev->miibus, phy_id, MII_BMCR);
timeout++;
} while ((bmcr & MII_BMCR) && (timeout < 100));
@@ -457,14 +454,14 @@ static int smsc95xx_phy_initialize(struct usbnet *dev)
return -EIO;
}
- smsc95xx_mdio_write(&dev->miidev, phy_id, MII_ADVERTISE,
+ smsc95xx_mdio_write(&dev->miibus, phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
ADVERTISE_PAUSE_ASYM);
/* read to clear */
- val = smsc95xx_mdio_read(&dev->miidev, phy_id, PHY_INT_SRC);
+ val = smsc95xx_mdio_read(&dev->miibus, phy_id, PHY_INT_SRC);
- smsc95xx_mdio_write(&dev->miidev, phy_id, PHY_INT_MASK,
+ smsc95xx_mdio_write(&dev->miibus, phy_id, PHY_INT_MASK,
PHY_INT_MASK_DEFAULT_);
netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n");
@@ -747,7 +744,7 @@ static int smsc95xx_bind(struct usbnet *dev)
dev->edev.get_ethaddr = smsc95xx_get_ethaddr;
dev->edev.set_ethaddr = smsc95xx_set_ethaddr;
- mii_register(&dev->miidev);
+ mdiobus_register(&dev->miibus);
return 0;
}
@@ -756,7 +753,7 @@ static void smsc95xx_unbind(struct usbnet *dev)
{
struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
- mii_unregister(&dev->miidev);
+ mdiobus_unregister(&dev->miibus);
if (pdata) {
netif_dbg(dev, ifdown, dev->net, "free pdata\n");
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index c7e360690e..80b4ae7b9e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -4,6 +4,7 @@
#include <asm/byteorder.h>
#include <errno.h>
#include <malloc.h>
+#include <linux/phy.h>
static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
{
@@ -160,8 +161,6 @@ static int usbnet_init(struct eth_device *edev)
return ret;
}
- miidev_restart_aneg(&dev->miidev);
-
return 0;
}
@@ -171,12 +170,8 @@ static int usbnet_open(struct eth_device *edev)
dev_dbg(&edev->dev, "%s\n",__func__);
- if (miidev_wait_aneg(&dev->miidev))
- return -1;
-
- miidev_print_status(&dev->miidev);
-
- return 0;
+ return phy_device_connect(edev, &dev->miibus, dev->phy_addr, NULL,
+ 0, PHY_INTERFACE_MODE_NA);
}
static void usbnet_halt(struct eth_device *edev)
diff --git a/drivers/nor/cfi_flash.c b/drivers/nor/cfi_flash.c
index 7ca36380a9..f65763a6e6 100644
--- a/drivers/nor/cfi_flash.c
+++ b/drivers/nor/cfi_flash.c
@@ -913,7 +913,6 @@ struct file_operations cfi_ops = {
.memmap = generic_memmap_ro,
};
-#ifdef CONFIG_PARTITION_NEED_MTD
static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
@@ -973,11 +972,11 @@ static void cfi_init_mtd(struct flash_info *info)
mtd->flags = MTD_CAP_NORFLASH;
info->cdev.mtd = mtd;
}
-#endif
static int cfi_probe (struct device_d *dev)
{
struct flash_info *info = xzalloc(sizeof(*info));
+ int cfinum;
dev->priv = (void *)info;
@@ -996,30 +995,46 @@ static int cfi_probe (struct device_d *dev)
dev_info(dev, "found cfi flash at %p, size %ld\n",
info->base, info->size);
- info->cdev.name = asprintf("nor%d", dev->id);
+ if (dev->id < 0)
+ cfinum = cdev_find_free_index("nor");
+ else
+ cfinum = dev->id;
+
+ info->cdev.name = asprintf("nor%d", cfinum);
info->cdev.size = info->size;
info->cdev.dev = dev;
info->cdev.ops = &cfi_ops;
info->cdev.priv = info;
-#ifdef CONFIG_PARTITION_NEED_MTD
- cfi_init_mtd(info);
-#endif
+ if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD))
+ cfi_init_mtd(info);
+
devfs_create(&info->cdev);
+ if (dev->device_node)
+ of_parse_partitions(info->cdev.name, dev->device_node);
+
return 0;
}
+static __maybe_unused struct of_device_id cfi_dt_ids[] = {
+ {
+ .compatible = "cfi-flash",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d cfi_driver = {
- .name = "cfi_flash",
- .probe = cfi_probe,
- .info = cfi_info,
+ .name = "cfi_flash",
+ .probe = cfi_probe,
+ .info = cfi_info,
+ .of_compatible = DRV_OF_COMPAT(cfi_dt_ids),
};
static int cfi_init(void)
{
- return register_driver(&cfi_driver);
+ return register_driver(&cfi_driver);
}
device_initcall(cfi_init);
-
diff --git a/drivers/nor/cfi_flash.h b/drivers/nor/cfi_flash.h
index ee4ea38297..8f818ba4aa 100644
--- a/drivers/nor/cfi_flash.h
+++ b/drivers/nor/cfi_flash.h
@@ -71,9 +71,7 @@ struct flash_info {
ulong addr_unlock2; /* unlock address 2 for AMD flash roms */
struct cfi_cmd_set *cfi_cmd_set;
struct cdev cdev;
-#ifdef CONFIG_PARTITION_NEED_MTD
struct mtd_info mtd;
-#endif
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
void *base;
diff --git a/drivers/nor/m25p80.c b/drivers/nor/m25p80.c
index 5713ad58fe..e3b5b95443 100644
--- a/drivers/nor/m25p80.c
+++ b/drivers/nor/m25p80.c
@@ -648,6 +648,9 @@ static const struct spi_device_id m25p_ids[] = {
{ "cat25c09", CAT25_INFO( 128, 8, 32, 2) },
{ "cat25c17", CAT25_INFO( 256, 8, 32, 2) },
{ "cat25128", CAT25_INFO(2048, 8, 64, 2) },
+
+ /* Micron */
+ { "n25q128", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
{ },
};
@@ -694,6 +697,74 @@ static struct file_operations m25p80_ops = {
.lseek = dev_lseek_default,
};
+static int m25p_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct m25p *flash = container_of(mtd, struct m25p, mtd);
+ ssize_t ret;
+
+ ret = flash->cdev.ops->read(&flash->cdev, buf, len, from, 0);
+ if (ret < 0) {
+ *retlen = 0;
+ return ret;
+ }
+
+ *retlen = ret;
+ return 0;
+}
+
+static int m25p_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct m25p *flash = container_of(mtd, struct m25p, mtd);
+ ssize_t ret;
+
+ ret = flash->cdev.ops->write(&flash->cdev, buf, len, to, 0);
+ if (ret < 0) {
+ *retlen = 0;
+ return ret;
+ }
+
+ *retlen = ret;
+ return 0;
+}
+
+static int m25p_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct m25p *flash = container_of(mtd, struct m25p, mtd);
+ ssize_t ret;
+
+ ret = flash->cdev.ops->erase(&flash->cdev, instr->len, instr->addr);
+
+ if (ret) {
+ instr->state = MTD_ERASE_FAILED;
+ return -EIO;
+ }
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
+}
+
+static void m25p_init_mtd(struct m25p *flash)
+{
+ struct mtd_info *mtd = &flash->mtd;
+
+ mtd->read = m25p_mtd_read;
+ mtd->write = m25p_mtd_write;
+ mtd->erase = m25p_mtd_erase;
+ mtd->size = flash->size;
+ mtd->name = flash->cdev.name;
+ mtd->erasesize = flash->erasesize;
+ mtd->writesize = 1;
+ mtd->subpage_sft = 0;
+ mtd->eraseregions = NULL;
+ mtd->numeraseregions = 0;
+ mtd->flags = MTD_CAP_NORFLASH;
+ flash->cdev.mtd = mtd;
+}
+
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -825,6 +896,9 @@ static int m25p_probe(struct device_d *dev)
dev_info(dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->size >> 10);
+ if (IS_ENABLED(CONFIG_PARTITION_NEED_MTD))
+ m25p_init_mtd(flash);
+
devfs_create(&flash->cdev);
return 0;
@@ -838,7 +912,7 @@ static struct driver_d epcs_flash_driver = {
static int epcs_init(void)
{
- register_driver(&epcs_flash_driver);
+ spi_register_driver(&epcs_flash_driver);
return 0;
}
diff --git a/drivers/nor/m25p80.h b/drivers/nor/m25p80.h
index 34bf2e259a..957900e3a2 100644
--- a/drivers/nor/m25p80.h
+++ b/drivers/nor/m25p80.h
@@ -46,7 +46,7 @@ struct spi_device_id {
struct m25p {
struct spi_device *spi;
struct flash_info *info;
- struct mtd_info mtd;
+ struct mtd_info mtd;
struct cdev cdev;
char *name;
u32 erasesize;
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
new file mode 100644
index 0000000000..95f10d025c
--- /dev/null
+++ b/drivers/of/Kconfig
@@ -0,0 +1,2 @@
+config OFDEVICE
+ bool
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
new file mode 100644
index 0000000000..c14aaec79f
--- /dev/null
+++ b/drivers/of/Makefile
@@ -0,0 +1,3 @@
+obj-y += base.o
+obj-y += gpio.o
+obj-y += partition.o
diff --git a/drivers/of/base.c b/drivers/of/base.c
new file mode 100644
index 0000000000..ebbaef85c1
--- /dev/null
+++ b/drivers/of/base.c
@@ -0,0 +1,802 @@
+/*
+ * base.c - basic devicetree functions
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * based on Linux devicetree support
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <common.h>
+#include <of.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <malloc.h>
+#include <init.h>
+#include <linux/ctype.h>
+
+/**
+ * struct alias_prop - Alias property in 'aliases' node
+ * @link: List node to link the structure in aliases_lookup list
+ * @alias: Alias property name
+ * @np: Pointer to device_node that the alias stands for
+ * @id: Index value from end of alias name
+ * @stem: Alias string without the index
+ *
+ * The structure represents one alias property of 'aliases' node as
+ * an entry in aliases_lookup list.
+ */
+struct alias_prop {
+ struct list_head link;
+ const char *alias;
+ struct device_node *np;
+ int id;
+ char stem[0];
+};
+
+static LIST_HEAD(aliases_lookup);
+
+static LIST_HEAD(phandle_list);
+
+static LIST_HEAD(allnodes);
+
+struct device_node *root_node;
+
+struct device_node *of_aliases;
+
+int of_n_addr_cells(struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#address-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+ } while (np->parent);
+ /* No #address-cells property for the root node */
+ return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_addr_cells);
+
+int of_n_size_cells(struct device_node *np)
+{
+ const __be32 *ip;
+
+ do {
+ if (np->parent)
+ np = np->parent;
+ ip = of_get_property(np, "#size-cells", NULL);
+ if (ip)
+ return be32_to_cpup(ip);
+ } while (np->parent);
+ /* No #size-cells property for the root node */
+ return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+EXPORT_SYMBOL(of_n_size_cells);
+
+static void of_bus_default_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ if (addrc)
+ *addrc = of_n_addr_cells(dev);
+ if (sizec)
+ *sizec = of_n_size_cells(dev);
+}
+
+void of_bus_count_cells(struct device_node *dev,
+ int *addrc, int *sizec)
+{
+ of_bus_default_count_cells(dev, addrc, sizec);
+}
+
+struct property *of_find_property(const struct device_node *node, const char *name)
+{
+ struct property *p;
+
+ list_for_each_entry(p, &node->properties, list)
+ if (!strcmp(p->name, name))
+ return p;
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_property);
+
+static void of_alias_add(struct alias_prop *ap, struct device_node *np,
+ int id, const char *stem, int stem_len)
+{
+ ap->np = np;
+ ap->id = id;
+ strncpy(ap->stem, stem, stem_len);
+ ap->stem[stem_len] = 0;
+ list_add_tail(&ap->link, &aliases_lookup);
+ pr_debug("adding DT alias:%s: stem=%s id=%i node=%s\n",
+ ap->alias, ap->stem, ap->id, np->full_name);
+}
+
+/**
+ * of_alias_scan - Scan all properties of 'aliases' node
+ *
+ * The function scans all the properties of 'aliases' node and populates
+ * the global lookup table with the properties. It returns the
+ * number of alias_prop found, or error code in error case.
+ */
+void of_alias_scan(void)
+{
+ struct property *pp;
+
+ of_aliases = of_find_node_by_path("/aliases");
+ if (!of_aliases)
+ return;
+
+ list_for_each_entry(pp, &of_aliases->properties, list) {
+ const char *start = pp->name;
+ const char *end = start + strlen(start);
+ struct device_node *np;
+ struct alias_prop *ap;
+ int id, len;
+
+ /* Skip those we do not want to proceed */
+ if (!strcmp(pp->name, "name") ||
+ !strcmp(pp->name, "phandle") ||
+ !strcmp(pp->name, "linux,phandle"))
+ continue;
+
+ np = of_find_node_by_path(pp->value);
+ if (!np)
+ continue;
+
+ /* walk the alias backwards to extract the id and work out
+ * the 'stem' string */
+ while (isdigit(*(end-1)) && end > start)
+ end--;
+ len = end - start;
+
+ id = simple_strtol(end, 0, 10);
+ if (id < 0)
+ continue;
+
+ /* Allocate an alias_prop with enough space for the stem */
+ ap = xzalloc(sizeof(*ap) + len + 1);
+ if (!ap)
+ continue;
+ ap->alias = start;
+ of_alias_add(ap, np, id, start, len);
+ }
+}
+
+/**
+ * of_alias_get_id - Get alias id for the given device_node
+ * @np: Pointer to the given device_node
+ * @stem: Alias stem of the given device_node
+ *
+ * The function travels the lookup table to get alias id for the given
+ * device_node and alias stem. It returns the alias id if find it.
+ */
+int of_alias_get_id(struct device_node *np, const char *stem)
+{
+ struct alias_prop *app;
+ int id = -ENODEV;
+
+ list_for_each_entry(app, &aliases_lookup, link) {
+ if (strcmp(app->stem, stem) != 0)
+ continue;
+
+ if (np == app->np) {
+ id = app->id;
+ break;
+ }
+ }
+
+ return id;
+}
+EXPORT_SYMBOL_GPL(of_alias_get_id);
+
+u64 of_translate_address(struct device_node *node, const __be32 *in_addr)
+{
+ struct property *p;
+ u64 addr = be32_to_cpu(*in_addr);
+
+ while (1) {
+ int na, nc;
+
+ if (!node->parent)
+ return addr;
+
+ node = node->parent;
+ p = of_find_property(node, "ranges");
+ if (!p && node->parent)
+ return OF_BAD_ADDR;
+ of_bus_count_cells(node, &na, &nc);
+ if (na != 1 || nc != 1) {
+ printk("%s: #size-cells != 1 or #address-cells != 1 "
+ "currently not supported\n", node->name);
+ return OF_BAD_ADDR;
+ }
+ }
+}
+EXPORT_SYMBOL(of_translate_address);
+
+/*
+ * of_find_node_by_phandle - Find a node given a phandle
+ * @handle: phandle of the node to find
+ */
+struct device_node *of_find_node_by_phandle(phandle phandle)
+{
+ struct device_node *node;
+
+ list_for_each_entry(node, &phandle_list, phandles)
+ if (node->phandle == phandle)
+ return node;
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_node_by_phandle);
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp)
+{
+ struct property *pp = of_find_property(np, name);
+
+ if (!pp)
+ return NULL;
+
+ if (lenp)
+ *lenp = pp->length;
+
+ return pp ? pp->value : NULL;
+}
+EXPORT_SYMBOL(of_get_property);
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+ const char *compat)
+{
+ const char *cp;
+ int cplen, l;
+
+ cp = of_get_property(device, "compatible", &cplen);
+ if (cp == NULL)
+ return 0;
+ while (cplen > 0) {
+ if (strcmp(cp, compat) == 0)
+ return 1;
+ l = strlen(cp) + 1;
+ cp += l;
+ cplen -= l;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(of_device_is_compatible);
+
+int of_match(struct device_d *dev, struct driver_d *drv)
+{
+ struct of_device_id *id;
+
+ id = drv->of_compatible;
+
+ while (id->compatible) {
+ if (of_device_is_compatible(dev->device_node, id->compatible) == 1) {
+ dev->of_id_entry = id;
+ return 0;
+ }
+ id++;
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL(of_match);
+
+/**
+ * of_property_read_u32_array - Find and read an array of 32 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_value: pointer to return value, modified only if return value is 0.
+ *
+ * Search for a property in a device node and read 32-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u32 value can be decoded.
+ */
+int of_property_read_u32_array(const struct device_node *np,
+ const char *propname, u32 *out_values,
+ size_t sz)
+{
+ struct property *prop = of_find_property(np, propname);
+ const __be32 *val;
+
+ if (!prop)
+ return -EINVAL;
+ if (!prop->value)
+ return -ENODATA;
+ if ((sz * sizeof(*out_values)) > prop->length)
+ return -EOVERFLOW;
+
+ val = prop->value;
+ while (sz--)
+ *out_values++ = be32_to_cpup(val++);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u32_array);
+
+/**
+ * of_parse_phandles_with_args - Find a node pointed by phandle in a list
+ * @np: pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies phandles' arguments count
+ * @index: index of a phandle to parse out
+ * @out_node: optional pointer to device_node struct pointer (will be filled)
+ * @out_args: optional pointer to arguments pointer (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_node and out_args, on error returns
+ * appropriate errno value.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ * #list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ * #list-cells = <1>;
+ * }
+ *
+ * node3 {
+ * list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
+ */
+int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
+ const char *cells_name, int index,
+ struct device_node **out_node,
+ const void **out_args)
+{
+ int ret = -EINVAL;
+ const __be32 *list;
+ const __be32 *list_end;
+ int size;
+ int cur_index = 0;
+ struct device_node *node = NULL;
+ const void *args = NULL;
+
+ list = of_get_property(np, list_name, &size);
+ if (!list) {
+ ret = -ENOENT;
+ goto err0;
+ }
+ list_end = list + size / sizeof(*list);
+
+ while (list < list_end) {
+ const __be32 *cells;
+ phandle phandle;
+
+ phandle = be32_to_cpup(list++);
+ args = list;
+
+ /* one cell hole in the list = <>; */
+ if (!phandle)
+ goto next;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ pr_debug("%s: could not find phandle %d\n",
+ np->full_name, phandle);
+ goto err0;
+ }
+
+ cells = of_get_property(node, cells_name, &size);
+ if (!cells || size != sizeof(*cells)) {
+ pr_debug("%s: could not get %s for %s\n",
+ np->full_name, cells_name, node->full_name);
+ goto err1;
+ }
+
+ list += be32_to_cpup(cells);
+ if (list > list_end) {
+ pr_debug("%s: insufficient arguments length\n",
+ np->full_name);
+ goto err1;
+ }
+next:
+ if (cur_index == index)
+ break;
+
+ node = NULL;
+ args = NULL;
+ cur_index++;
+ }
+
+ if (!node) {
+ /*
+ * args w/o node indicates that the loop above has stopped at
+ * the 'hole' cell. Report this differently.
+ */
+ if (args)
+ ret = -EEXIST;
+ else
+ ret = -ENOENT;
+ goto err0;
+ }
+
+ if (out_node)
+ *out_node = node;
+ if (out_args)
+ *out_args = args;
+
+ return 0;
+err1:
+err0:
+ pr_debug("%s failed with status %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL(of_parse_phandles_with_args);
+
+/**
+ * of_machine_is_compatible - Test root of device tree for a given compatible value
+ * @compat: compatible string to look for in root node's compatible property.
+ *
+ * Returns true if the root node has the given value in its
+ * compatible property.
+ */
+int of_machine_is_compatible(const char *compat)
+{
+ if (!root_node)
+ return 0;
+
+ return of_device_is_compatible(root_node, compat);
+}
+EXPORT_SYMBOL(of_machine_is_compatible);
+
+/**
+ * of_find_node_by_path - Find a node matching a full OF path
+ * @path: The full path to match
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_find_node_by_path(const char *path)
+{
+ struct device_node *np;
+
+ list_for_each_entry(np, &allnodes, list) {
+ if (np->full_name && (strcmp(np->full_name, path) == 0))
+ break;
+ }
+ return np;
+}
+EXPORT_SYMBOL(of_find_node_by_path);
+
+struct device_node *of_get_root_node(void)
+{
+ return root_node;
+}
+
+static int of_node_disabled(struct device_node *node)
+{
+ struct property *p;
+
+ p = of_find_property(node, "status");
+ if (p) {
+ if (!strcmp("disabled", p->value))
+ return 1;
+ }
+ return 0;
+}
+
+void of_print_nodes(struct device_node *node, int indent)
+{
+ struct device_node *n;
+ struct property *p;
+ int i;
+
+ if (!node)
+ return;
+
+ if (of_node_disabled(node))
+ return;
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+
+ printf("%s%s\n", node->name, node->name ? " {" : "{");
+
+ list_for_each_entry(p, &node->properties, list) {
+ for (i = 0; i < indent + 1; i++)
+ printf("\t");
+ printf("%s: ", p->name);
+ of_print_property(p->value, p->length);
+ printf("\n");
+ }
+
+ list_for_each_entry(n, &node->children, parent_list) {
+ of_print_nodes(n, indent + 1);
+ }
+
+ for (i = 0; i < indent; i++)
+ printf("\t");
+ printf("};\n");
+}
+
+static struct device_node *new_device_node(struct device_node *parent)
+{
+ struct device_node *node;
+
+ node = xzalloc(sizeof(*node));
+ node->parent = parent;
+ if (parent)
+ list_add_tail(&node->parent_list, &parent->children);
+
+ INIT_LIST_HEAD(&node->children);
+ INIT_LIST_HEAD(&node->properties);
+
+ return node;
+}
+
+static struct property *new_property(struct device_node *node, const char *name,
+ const void *data, int len)
+{
+ struct property *prop;
+
+ prop = xzalloc(sizeof(*prop));
+
+ prop->name = strdup(name);
+ prop->length = len;
+ prop->value = xzalloc(len);
+ memcpy(prop->value, data, len);
+
+ list_add_tail(&prop->list, &node->properties);
+
+ return prop;
+}
+
+static struct device_d *add_of_device(struct device_node *node)
+{
+ struct device_d *dev;
+ char *name, *at;
+ const struct property *cp;
+
+ if (of_node_disabled(node))
+ return NULL;
+
+ cp = of_get_property(node, "compatible", NULL);
+ if (!cp)
+ return NULL;
+
+ dev = xzalloc(sizeof(*dev));
+
+ name = xstrdup(node->name);
+ at = strchr(name, '@');
+ if (at) {
+ *at = 0;
+ snprintf(dev->name, MAX_DRIVER_NAME, "%s.%s", at + 1, name);
+ } else {
+ strncpy(dev->name, node->name, MAX_DRIVER_NAME);
+ }
+
+ dev->id = DEVICE_ID_SINGLE;
+ dev->resource = node->resource;
+ dev->num_resources = 1;
+ dev->device_node = node;
+ node->device = dev;
+
+ debug("register device 0x%08x\n", node->resource[0].start);
+
+ register_device(dev);
+
+ free(name);
+
+ return dev;
+}
+EXPORT_SYMBOL(add_of_device);
+
+static int add_of_device_resource(struct device_node *node)
+{
+ struct property *reg;
+ u64 address, size;
+ struct resource *res;
+ struct device_d *dev;
+ phandle phandle;
+ int ret;
+
+ ret = of_property_read_u32(node, "phandle", &phandle);
+ if (!ret) {
+ node->phandle = phandle;
+ list_add_tail(&node->phandles, &phandle_list);
+ }
+
+ reg = of_find_property(node, "reg");
+ if (!reg)
+ return -ENODEV;
+
+ address = of_translate_address(node, reg->value);
+ if (address == OF_BAD_ADDR)
+ return -EINVAL;
+
+ size = be32_to_cpu(((u32 *)reg->value)[1]);
+
+ /*
+ * A device may already be registered as platform_device.
+ * Instead of registering the same device again, just
+ * add this node to the existing device.
+ */
+ for_each_device(dev) {
+ if (!dev->resource)
+ continue;
+ if (dev->resource->start == address) {
+ debug("connecting %s to %s\n", node->name, dev_name(dev));
+ node->device = dev;
+ dev->device_node = node;
+ node->resource = dev->resource;
+ return 0;
+ }
+ }
+
+ res = xzalloc(sizeof(*res));
+ res->start = address;
+ res->end = address + size - 1;
+ res->flags = IORESOURCE_MEM;
+
+ node->resource = res;
+
+ add_of_device(node);
+
+ return 0;
+}
+
+void of_free(struct device_node *node)
+{
+ struct device_node *n, *nt;
+ struct property *p, *pt;
+
+ if (!node)
+ return;
+
+ list_for_each_entry_safe(p, pt, &node->properties, list) {
+ list_del(&p->list);
+ free(p->name);
+ free(p->value);
+ free(p);
+ }
+
+ list_for_each_entry_safe(n, nt, &node->children, parent_list) {
+ of_free(n);
+ }
+
+ if (node->parent)
+ list_del(&node->parent_list);
+
+ if (node->device)
+ node->device->device_node = NULL;
+ else
+ free(node->resource);
+
+ free(node->name);
+ free(node->full_name);
+ free(node);
+}
+
+static void __of_probe(struct device_node *node)
+{
+ struct device_node *n;
+
+ if (node->device)
+ return;
+
+ add_of_device_resource(node);
+
+ list_for_each_entry(n, &node->children, parent_list)
+ __of_probe(n);
+}
+
+int of_probe(void)
+{
+ if(!root_node)
+ return -ENODEV;
+
+ __of_probe(root_node);
+
+ return 0;
+}
+
+/*
+ * Parse a flat device tree binary blob and store it in the barebox
+ * internal tree format,
+ */
+int of_parse_dtb(struct fdt_header *fdt)
+{
+ const void *nodep; /* property node pointer */
+ int nodeoffset; /* node offset from libfdt */
+ int nextoffset; /* next node offset from libfdt */
+ uint32_t tag; /* tag */
+ int len; /* length of the property */
+ int level = 0; /* keep track of nesting level */
+ const struct fdt_property *fdt_prop;
+ const char *pathp;
+ int depth = 10000;
+ struct device_node *node = NULL;
+ char buf[1024];
+ int ret;
+
+ if (root_node)
+ return -EBUSY;
+
+ nodeoffset = fdt_path_offset(fdt, "/");
+ if (nodeoffset < 0) {
+ /*
+ * Not found or something else bad happened.
+ */
+ printf ("libfdt fdt_path_offset() returned %s\n",
+ fdt_strerror(nodeoffset));
+ return -EINVAL;
+ }
+
+ while (1) {
+ tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
+ switch (tag) {
+ case FDT_BEGIN_NODE:
+ pathp = fdt_get_name(fdt, nodeoffset, NULL);
+
+ if (pathp == NULL)
+ pathp = "/* NULL pointer error */";
+
+ ret = fdt_get_path(fdt, nodeoffset, buf, 1024);
+ if (ret)
+ return -EINVAL;
+
+ node = new_device_node(node);
+ if (!node->parent)
+ root_node = node;
+ node->full_name = xstrdup(buf);
+ node->name = xstrdup(pathp);
+ list_add_tail(&node->list, &allnodes);
+ break;
+ case FDT_END_NODE:
+ node = node->parent;
+ break;
+ case FDT_PROP:
+ fdt_prop = fdt_offset_ptr(fdt, nodeoffset,
+ sizeof(*fdt_prop));
+ pathp = fdt_string(fdt,
+ fdt32_to_cpu(fdt_prop->nameoff));
+ len = fdt32_to_cpu(fdt_prop->len);
+ nodep = fdt_prop->data;
+ new_property(node, pathp, nodep, len);
+ break;
+ case FDT_NOP:
+ break;
+ case FDT_END:
+ of_alias_scan();
+ return 0;
+ default:
+ if (level <= depth)
+ printf("Unknown tag 0x%08X\n", tag);
+ return -EINVAL;
+ }
+ nodeoffset = nextoffset;
+ }
+
+ return 0;
+}
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
new file mode 100644
index 0000000000..d4314f3e28
--- /dev/null
+++ b/drivers/of/gpio.c
@@ -0,0 +1,28 @@
+#define DEBUG
+
+#include <common.h>
+#include <errno.h>
+#include <of.h>
+#include <gpio.h>
+
+int of_get_named_gpio(struct device_node *np,
+ const char *propname, int index)
+{
+ int ret;
+ struct device_node *gpio_np;
+ const void *gpio_spec;
+
+ ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
+ &gpio_np, &gpio_spec);
+ if (ret) {
+ pr_debug("%s: can't parse gpios property: %d\n", __func__, ret);
+ return -EINVAL;
+ }
+
+ ret = gpio_get_num(gpio_np->device, be32_to_cpup(gpio_spec));
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
diff --git a/drivers/of/partition.c b/drivers/of/partition.c
new file mode 100644
index 0000000000..6a57a6036e
--- /dev/null
+++ b/drivers/of/partition.c
@@ -0,0 +1,64 @@
+/*
+ * partition.c - devicetree partition parsing
+ *
+ * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * based on Linux devicetree support
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <common.h>
+#include <of.h>
+#include <malloc.h>
+#include <linux/mtd/mtd.h>
+
+int of_parse_partitions(const char *cdevname,
+ struct device_node *node)
+{
+ struct device_node *n;
+ const char *partname;
+ char *filename;
+
+ device_node_for_nach_child(node, n) {
+ const __be32 *reg;
+ unsigned long offset, size;
+ const char *name;
+ int len;
+ unsigned long flags = 0;
+
+ reg = of_get_property(n, "reg", &len);
+ if (!reg)
+ continue;
+
+ offset = be32_to_cpu(reg[0]);
+ size = be32_to_cpu(reg[1]);
+
+ partname = of_get_property(n, "label", &len);
+ if (!partname)
+ partname = of_get_property(n, "name", &len);
+ name = (char *)partname;
+
+ debug("add partition: %s.%s 0x%08lx 0x%08lx\n", cdevname, partname, offset, size);
+
+ if (of_get_property(n, "read-only", &len))
+ flags = DEVFS_PARTITION_READONLY;
+
+ filename = asprintf("%s.%s", cdevname, partname);
+
+ devfs_add_partition(cdevname, offset, size, flags, filename);
+
+ free(filename);
+ }
+
+ return 0;
+}
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index c6e61ee104..58c69e5c2d 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -31,6 +31,7 @@
#include <linux/amba/serial.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/amba/bus.h>
/*
* We wrap our port structure around the generic console_device.
@@ -40,6 +41,23 @@ struct amba_uart_port {
struct console_device uart; /* uart */
struct clk *clk; /* uart clock */
u32 uartclk;
+ struct vendor_data *vendor;
+};
+
+/* There is by now at least one vendor with differing details, so handle it */
+struct vendor_data {
+ unsigned int lcrh_tx;
+ unsigned int lcrh_rx;
+};
+
+static struct vendor_data vendor_arm = {
+ .lcrh_tx = UART011_LCRH,
+ .lcrh_rx = UART011_LCRH,
+};
+
+static struct vendor_data vendor_st = {
+ .lcrh_tx = ST_UART011_LCRH_TX,
+ .lcrh_rx = ST_UART011_LCRH_RX,
};
static inline struct amba_uart_port *
@@ -112,13 +130,27 @@ static int pl011_tstc(struct console_device *cdev)
return !(readl(uart->base + UART01x_FR) & UART01x_FR_RXFE);
}
+static void pl011_rlcr(struct amba_uart_port *uart, u32 lcr)
+{
+ struct vendor_data *vendor = uart->vendor;
+
+ writew(lcr, uart->base + vendor->lcrh_rx);
+ if (vendor->lcrh_tx != vendor->lcrh_rx) {
+ int i;
+ /*
+ * Wait 10 PCLKs before writing LCRH_TX register,
+ * to get this delay write read only register 10 times
+ */
+ for (i = 0; i < 10; ++i)
+ writew(0xff, uart->base + UART011_MIS);
+ writew(lcr, uart->base + vendor->lcrh_tx);
+ }
+}
+
int pl011_init_port (struct console_device *cdev)
{
- struct device_d *dev = cdev->dev;
struct amba_uart_port *uart = to_amba_uart_port(cdev);
- uart->base = dev_request_mem_region(dev, 0);
-
/*
** First, disable everything.
*/
@@ -138,8 +170,7 @@ int pl011_init_port (struct console_device *cdev)
/*
** Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled.
*/
- writel((UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN),
- uart->base + UART011_LCRH);
+ pl011_rlcr(uart, UART01x_LCRH_WLEN_8 | UART01x_LCRH_FEN);
/*
** Finally, enable the UART
@@ -150,19 +181,21 @@ int pl011_init_port (struct console_device *cdev)
return 0;
}
-static int pl011_probe(struct device_d *dev)
+static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
{
struct amba_uart_port *uart;
struct console_device *cdev;
uart = xzalloc(sizeof(struct amba_uart_port));
- uart->clk = clk_get(dev, NULL);
+ uart->clk = clk_get(&dev->dev, NULL);
+ uart->base = amba_get_mem_region(dev);
+ uart->vendor = (void*)id->data;
if (IS_ERR(uart->clk))
return PTR_ERR(uart->clk);
cdev = &uart->uart;
- cdev->dev = dev;
+ cdev->dev = &dev->dev;
cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
cdev->tstc = pl011_tstc;
cdev->putc = pl011_putc;
@@ -178,14 +211,31 @@ static int pl011_probe(struct device_d *dev)
return 0;
}
-static struct driver_d pl011_driver = {
- .name = "uart-pl011",
- .probe = pl011_probe,
+static struct amba_id pl011_ids[] = {
+ {
+ .id = 0x00041011,
+ .mask = 0x000fffff,
+ .data = &vendor_arm,
+ },
+ {
+ .id = 0x00380802,
+ .mask = 0x00ffffff,
+ .data = &vendor_st,
+ },
+ { 0, 0 },
+};
+
+struct amba_driver pl011_driver = {
+ .drv = {
+ .name = "uart-pl011",
+ },
+ .probe = pl011_probe,
+ .id_table = pl011_ids,
};
static int pl011_init(void)
{
- register_driver(&pl011_driver);
+ amba_driver_register(&pl011_driver);
return 0;
}
diff --git a/drivers/serial/serial_imx.c b/drivers/serial/serial_imx.c
index 827e838ff2..012ab028a1 100644
--- a/drivers/serial/serial_imx.c
+++ b/drivers/serial/serial_imx.c
@@ -354,10 +354,23 @@ static void imx_serial_remove(struct device_d *dev)
free(priv);
}
+static __maybe_unused struct of_device_id imx_serial_dt_ids[] = {
+ {
+ .compatible = "fsl,imx1-uart",
+ .data = 0,
+ }, {
+ .compatible = "fsl,imx21-uart",
+ .data = 1,
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d imx_serial_driver = {
- .name = "imx_serial",
- .probe = imx_serial_probe,
+ .name = "imx_serial",
+ .probe = imx_serial_probe,
.remove = imx_serial_remove,
+ .of_compatible = DRV_OF_COMPAT(imx_serial_dt_ids),
};
static int imx_serial_init(void)
diff --git a/drivers/spi/imx_spi.c b/drivers/spi/imx_spi.c
index bdd6e8172a..c3dc6cc863 100644
--- a/drivers/spi/imx_spi.c
+++ b/drivers/spi/imx_spi.c
@@ -20,6 +20,7 @@
#include <spi/spi.h>
#include <xfuncs.h>
#include <io.h>
+#include <errno.h>
#include <gpio.h>
#include <mach/spi.h>
#include <mach/generic.h>
@@ -491,6 +492,32 @@ static struct spi_imx_devtype_data spi_imx_devtype_data[] = {
#endif
};
+static int imx_spi_dt_probe(struct imx_spi *imx)
+{
+ struct device_node *node = imx->master.dev->device_node;
+ int ret, i;
+ u32 num_cs;
+
+ if (!node)
+ return -ENODEV;
+
+ ret = of_property_read_u32(node, "fsl,spi-num-chipselects", &num_cs);
+ if (ret)
+ return ret;
+
+ imx->master.num_chipselect = num_cs;
+ imx->cs_array = xzalloc(sizeof(u32) * num_cs);
+
+ for (i = 0; i < num_cs; i++) {
+ int cs_gpio = of_get_named_gpio(node, "cs-gpios", i);
+ imx->cs_array[i] = cs_gpio;
+ }
+
+ spi_of_register_slaves(&imx->master, node);
+
+ return 0;
+}
+
static int imx_spi_probe(struct device_d *dev)
{
struct spi_master *master;
@@ -505,8 +532,13 @@ static int imx_spi_probe(struct device_d *dev)
master->setup = imx_spi_setup;
master->transfer = imx_spi_transfer;
- master->num_chipselect = pdata->num_chipselect;
- imx->cs_array = pdata->chipselect;
+ if (pdata) {
+ master->num_chipselect = pdata->num_chipselect;
+ imx->cs_array = pdata->chipselect;
+ } else {
+ if (IS_ENABLED(CONFIG_OFDEVICE))
+ imx_spi_dt_probe(imx);
+ }
#ifdef CONFIG_DRIVER_SPI_IMX_0_0
if (cpu_is_mx27())
@@ -532,9 +564,22 @@ static int imx_spi_probe(struct device_d *dev)
return 0;
}
+static __maybe_unused struct of_device_id imx_spi_dt_ids[] = {
+ {
+ .compatible = "fsl,imx27-cspi",
+ }, {
+ .compatible = "fsl,imx35-cspi",
+ }, {
+ .compatible = "fsl,imx51-ecspi",
+ }, {
+ /* sentinel */
+ }
+};
+
static struct driver_d imx_spi_driver = {
.name = "imx_spi",
.probe = imx_spi_probe,
+ .of_compatible = DRV_OF_COMPAT(imx_spi_dt_ids),
};
static int imx_spi_init(void)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 39eae4eed7..44040e5f62 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -23,6 +23,8 @@
#include <xfuncs.h>
#include <malloc.h>
#include <errno.h>
+#include <init.h>
+#include <of.h>
/* SPI devices should normally not be created by SPI device drivers; that
* would make them board-specific. Similarly with SPI master drivers.
@@ -73,10 +75,12 @@ struct spi_device *spi_new_device(struct spi_master *master,
proxy->mode = chip->mode;
proxy->bits_per_word = chip->bits_per_word ? chip->bits_per_word : 8;
proxy->dev.platform_data = chip->platform_data;
+ proxy->dev.bus = &spi_bus;
strcpy(proxy->dev.name, chip->name);
/* allocate a free id for this chip */
proxy->dev.id = DEVICE_ID_DYNAMIC;
proxy->dev.type_data = proxy;
+ proxy->dev.device_node = chip->device_node;
dev_add_child(master->dev, &proxy->dev);
/* drivers may modify this initial i/o setup */
@@ -96,6 +100,27 @@ fail:
}
EXPORT_SYMBOL(spi_new_device);
+#ifdef CONFIG_OFDEVICE
+void spi_of_register_slaves(struct spi_master *master, struct device_node *node)
+{
+ struct device_node *n;
+ struct spi_board_info chip;
+ struct property *reg;
+
+ device_node_for_nach_child(node, n) {
+ chip.name = n->name;
+ chip.bus_num = master->bus_num;
+ chip.max_speed_hz = 300000; /* FIXME */
+ reg = of_find_property(n, "reg");
+ if (!reg)
+ continue;
+ chip.chip_select = of_read_number(reg->value, 1);
+ chip.device_node = n;
+ spi_register_board_info(&chip, 1);
+ }
+}
+#endif
+
/**
* spi_register_board_info - register SPI devices for a given board
* @info: array of chip descriptors
@@ -150,6 +175,8 @@ static void scan_boardinfo(struct spi_master *master)
}
}
+static LIST_HEAD(spi_master_list);
+
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
@@ -182,6 +209,8 @@ int spi_register_master(struct spi_master *master)
if (master->num_chipselect == 0)
return -EINVAL;
+ list_add_tail(&master->list, &spi_master_list);
+
/* populate children from any spi device tables */
scan_boardinfo(master);
status = 0;
@@ -236,3 +265,35 @@ int spi_write_then_read(struct spi_device *spi,
return status;
}
EXPORT_SYMBOL(spi_write_then_read);
+
+static int spi_match(struct device_d *dev, struct driver_d *drv)
+{
+ if (IS_ENABLED(CONFIG_OFDEVICE) && dev->device_node &&
+ drv->of_compatible)
+ return of_match(dev, drv);
+
+ return strcmp(dev->name, drv->name) ? -1 : 0;
+}
+
+static int spi_probe(struct device_d *dev)
+{
+ return dev->driver->probe(dev);
+}
+
+static void spi_remove(struct device_d *dev)
+{
+ dev->driver->remove(dev);
+}
+
+struct bus_type spi_bus = {
+ .name = "spi",
+ .match = spi_match,
+ .probe = spi_probe,
+ .remove = spi_remove,
+};
+
+static int spi_bus_init(void)
+{
+ return bus_register(&spi_bus);
+}
+pure_initcall(spi_bus_init);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 662705ea5f..9dc931bdc6 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1418,3 +1418,8 @@ struct bus_type usb_bus_type = {
.remove = usb_remove,
};
+static int usb_bus_init(void)
+{
+ return bus_register(&usb_bus_type);
+}
+pure_initcall(usb_bus_init);
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index d885570b24..ae6ff74cab 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -125,6 +125,7 @@ int register_framebuffer(struct fb_info *info)
sprintf(dev->name, "fb");
+ info->dev.bus = &fb_bus;
register_device(&info->dev);
dev_add_param(dev, "enable", fb_enable_set, NULL, 0);
dev_set_param(dev, "enable", "0");
@@ -160,19 +161,41 @@ static void fb_info(struct device_d *dev)
printf("\n");
}
-static int fb_probe(struct device_d *hw_dev)
+static struct driver_d fb_driver = {
+ .name = "fb",
+ .info = fb_info,
+};
+
+static int fb_match(struct device_d *dev, struct driver_d *drv)
{
return 0;
}
-static struct driver_d fb_driver = {
- .name = "fb",
+static int fb_probe(struct device_d *dev)
+{
+ return 0;
+}
+
+static void fb_remove(struct device_d *dev)
+{
+}
+
+struct bus_type fb_bus = {
+ .name = "fb",
+ .match = fb_match,
.probe = fb_probe,
- .info = fb_info,
+ .remove = fb_remove,
};
+static int fb_bus_init(void)
+{
+ return bus_register(&fb_bus);
+}
+pure_initcall(fb_bus_init);
+
static int fb_init_driver(void)
{
+ fb_driver.bus = &fb_bus;
register_driver(&fb_driver);
return 0;
}
diff --git a/fs/fat/ff.c b/fs/fat/ff.c
index 66db1d6b50..33f8b6195d 100644
--- a/fs/fat/ff.c
+++ b/fs/fat/ff.c
@@ -93,6 +93,7 @@
#include <errno.h>
#include <malloc.h>
#include <linux/ctype.h>
+#include <filetype.h>
#include "ff.h" /* FatFs configurations and declarations */
#include "diskio.h" /* Declarations of low level disk I/O functions */
@@ -1531,29 +1532,20 @@ int follow_path ( /* 0(0): successful, !=0: error code */
/*
* Load boot record and check if it is an FAT boot record
*/
-static int check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
+static enum filetype check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
FATFS *fs, /* File system object */
- DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
+ DWORD sect, /* Sector# (lba) to check if it is an FAT boot record or not */
+ DWORD *bootsec
)
{
- int ret;
+ enum filetype ret;
/* Load boot record */
ret = disk_read(fs, fs->win, sect, 1);
if (ret)
- return ret;
- /* Check record signature (always placed at offset 510 even if the sector size is>512) */
- if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)
- return -ENODEV;
-
- /* Check "FAT" string */
- if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
- return 0;
-
- if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
- return 0;
+ return filetype_unknown;
- return -ENODEV;
+ return is_fat_or_mbr(fs->win, bootsec);
}
/*
@@ -1565,8 +1557,10 @@ static int chk_mounted ( /* 0(0): successful, !=0: any error occurred */
)
{
BYTE fmt, b;
+ DWORD first_boot_sect;
DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
WORD nrsv;
+ enum filetype type;
INIT_LIST_HEAD(&fs->dirtylist);
@@ -1579,9 +1573,16 @@ static int chk_mounted ( /* 0(0): successful, !=0: any error occurred */
return -EIO;
#endif
/* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
- fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
- if (fmt)
- return fmt; /* No FAT volume is found */
+ type = check_fs(fs, bsect = 0, &first_boot_sect); /* Check sector 0 if it is a VBR */
+ if (type == filetype_mbr) {
+ /* Sector 0 is an MBR, now check for FAT in the first partition */
+ type = check_fs(fs, bsect = first_boot_sect, NULL);
+ if (type != filetype_fat)
+ return -ENODEV;
+ }
+
+ if (type == filetype_unknown)
+ return -ENODEV;
/* Following code initializes the file system object */
diff --git a/fs/fs.c b/fs/fs.c
index bbee12404b..b9a1f17dfc 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1138,6 +1138,12 @@ struct bus_type fs_bus = {
.remove = fs_remove,
};
+static int fs_bus_init(void)
+{
+ return bus_register(&fs_bus);
+}
+pure_initcall(fs_bus_init);
+
int register_fs_driver(struct fs_driver_d *fsdrv)
{
fsdrv->drv.bus = &fs_bus;
diff --git a/include/common.h b/include/common.h
index 3e5204d3d8..c1f44b402c 100644
--- a/include/common.h
+++ b/include/common.h
@@ -146,11 +146,11 @@ static inline void dump_stack(void)
#define MEMAREA_SIZE_SPECIFIED 1
struct memarea_info {
- struct device_d *device;
+ struct device_d *device;
unsigned long start;
unsigned long end;
unsigned long size;
- unsigned long flags;
+ unsigned long flags;
};
int parse_area_spec(const char *str, loff_t *start, loff_t *size);
diff --git a/include/driver.h b/include/driver.h
index 30b2089cd8..85a0c729c4 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -21,6 +21,7 @@
#include <linux/list.h>
#include <linux/ioport.h>
+#include <of.h>
#define MAX_DRIVER_NAME 32
#define FORMAT_DRIVER_NAME_ID "%s%d"
@@ -56,6 +57,11 @@
struct filep;
struct bus_type;
+struct platform_device_id {
+ const char *name;
+ unsigned long driver_data;
+};
+
/** @brief Describes a particular device present in the system */
struct device_d {
/*! This member (and 'type' described below) is used to match with a
@@ -82,6 +88,7 @@ struct device_d {
struct driver_d *driver; /*! The driver for this device */
struct list_head list; /* The list of all devices */
+ struct list_head bus_list; /* our bus */
struct list_head children; /* our children */
struct list_head sibling;
struct list_head active; /* The list of all devices which have a driver */
@@ -95,6 +102,11 @@ struct device_d {
struct list_head parameters;
struct list_head cdevs;
+
+ struct platform_device_id *id_entry;
+ struct device_node *device_node;
+
+ struct of_device_id *of_id_entry;
};
/** @brief Describes a driver present in the system */
@@ -104,6 +116,7 @@ struct driver_d {
const char *name;
struct list_head list;
+ struct list_head bus_list; /* our bus */
/*! Called if an instance of a device is found */
int (*probe) (struct device_d *);
@@ -115,6 +128,9 @@ struct driver_d {
void (*shortinfo) (struct device_d *);
struct bus_type *bus;
+
+ struct platform_device_id *id_table;
+ struct of_device_id *of_compatible;
};
/*@}*/ /* do not delete, doxygen relevant */
@@ -329,9 +345,9 @@ static inline int dev_close_default(struct device_d *dev, struct filep *f)
/* debugging and troubleshooting/diagnostic helpers. */
-#define dev_printf(dev, format, arg...) \
- printf("%s@%s: " format , (dev)->name , \
- dev_name(dev) , ## arg)
+int dev_printf(const struct device_d *dev, const char *format, ...)
+ __attribute__ ((format(__printf__, 2, 3)));
+
#define dev_emerg(dev, format, arg...) \
dev_printf((dev) , format , ## arg)
@@ -363,8 +379,26 @@ struct bus_type {
void (*remove)(struct device_d *dev);
struct list_head list;
+ struct list_head device_list;
+ struct list_head driver_list;
};
+int bus_register(struct bus_type *bus);
+
+extern struct list_head bus_list;
+
+/* Iterate over all buses
+ */
+#define for_each_bus(bus) list_for_each_entry(bus, &bus_list, list)
+
+/* Iterate over all devices of a bus
+ */
+#define bus_for_each_device(bus, dev) list_for_each_entry(dev, &bus->device_list, bus_list)
+
+/* Iterate over all drivers of a bus
+ */
+#define bus_for_each_driver(bus, drv) list_for_each_entry(drv, &bus->driver_list, bus_list)
+
extern struct bus_type platform_bus;
struct file_operations {
@@ -419,5 +453,10 @@ int devfs_add_partition(const char *devname, loff_t offset, loff_t size,
int flags, const char *name);
int devfs_del_partition(const char *name);
+#define DRV_OF_COMPAT(compat) \
+ IS_ENABLED(CONFIG_OFDEVICE) ? (compat) : NULL
+
+int dev_get_drvdata(struct device_d *dev, unsigned long *data);
+
#endif /* DRIVER_H */
diff --git a/include/fb.h b/include/fb.h
index 41deb8c696..c5944184b1 100644
--- a/include/fb.h
+++ b/include/fb.h
@@ -110,5 +110,7 @@ int register_framebuffer(struct fb_info *info);
#define FBIO_ENABLE _IO('F', 2)
#define FBIO_DISABLE _IO('F', 3)
+extern struct bus_type fb_bus;
+
#endif /* __FB_H */
diff --git a/include/fec.h b/include/fec.h
index 2d2fc2a2e5..94cb6edd19 100644
--- a/include/fec.h
+++ b/include/fec.h
@@ -21,6 +21,8 @@
#ifndef __INCLUDE_NETWORK_FEC_H
#define __INCLUDE_NETWORK_FEC_H
+#include <linux/phy.h>
+
/*
* Supported phy types on this platform
*/
@@ -39,6 +41,7 @@ typedef enum {
struct fec_platform_data {
xceiver_type xcv_type;
int phy_addr;
+ void (*phy_init)(struct phy_device *dev);
};
#endif /* __INCLUDE_NETWORK_FEC_H */
diff --git a/include/filetype.h b/include/filetype.h
index 179ec0f5eb..0b6cd24a6d 100644
--- a/include/filetype.h
+++ b/include/filetype.h
@@ -19,10 +19,30 @@ enum filetype {
filetype_sh,
filetype_mips_barebox,
filetype_fat,
+ filetype_mbr,
+ filetype_bmp,
+ filetype_png,
};
const char *file_type_to_string(enum filetype f);
enum filetype file_detect_type(void *_buf);
enum filetype file_name_detect_type(const char *filename);
+enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec);
+
+#define ARM_HEAD_SIZE 0x30
+#define ARM_HEAD_MAGICWORD_OFFSET 0x20
+#define ARM_HEAD_SIZE_OFFSET 0x2C
+
+#ifdef CONFIG_ARM
+static inline int is_barebox_arm_head(const char *head)
+{
+ return !strcmp(head + ARM_HEAD_MAGICWORD_OFFSET, "barebox");
+}
+#else
+static inline int is_barebox_arm_head(const char *head)
+{
+ return 0;
+}
+#endif
#endif /* __FILE_TYPE_H */
diff --git a/include/globalvar.h b/include/globalvar.h
index 7cc3976f6b..ddf885f18e 100644
--- a/include/globalvar.h
+++ b/include/globalvar.h
@@ -1,6 +1,7 @@
#ifndef __GLOBALVAR_H
#define __GLOBALVAR_H
+#ifdef CONFIG_GLOBALVAR
int globalvar_add_simple(const char *name);
int globalvar_add(const char *name,
@@ -8,5 +9,27 @@ int globalvar_add(const char *name,
const char *(*get)(struct device_d *, struct param_d *p),
unsigned long flags);
char *globalvar_get_match(const char *match, const char *seperator);
+void globalvar_set_match(const char *match, const char *val);
+#else
+static inline int globalvar_add_simple(const char *name)
+{
+ return 0;
+}
+
+static inline int globalvar_add(const char *name,
+ int (*set)(struct device_d *dev, struct param_d *p, const char *val),
+ const char *(*get)(struct device_d *, struct param_d *p),
+ unsigned long flags)
+{
+ return 0;
+}
+
+static inline char *globalvar_get_match(const char *match, const char *seperator)
+{
+ return NULL;
+}
+
+static inline void globalvar_set_match(const char *match, const char *val) {}
+#endif
#endif /* __GLOBALVAR_H */
diff --git a/include/graphic_utils.h b/include/graphic_utils.h
new file mode 100644
index 0000000000..9909b6c873
--- /dev/null
+++ b/include/graphic_utils.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2
+ */
+
+#ifndef __GRAPHIC_UTILS_H__
+#define __GRAPHIC_UTILS_H__
+
+void rgba_blend(struct fb_info *info, void *image, void* dest, int height,
+ int width, int startx, int starty, bool is_rgba);
+void set_pixel(struct fb_info *info, void *adr, u32 px);
+void set_rgb_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b);
+void set_rgba_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b, u8 a);
+void memset_pixel(struct fb_info *info, void* buf, u32 color, size_t size);
+
+#endif /* __GRAPHIC_UTILS_H__ */
diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
index c3e176354d..de2a7ea27d 100644
--- a/include/i2c/i2c.h
+++ b/include/i2c/i2c.h
@@ -139,4 +139,12 @@ extern int i2c_write_reg(struct i2c_client *client, u32 addr, const u8 *buf, u16
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+extern struct bus_type i2c_bus;
+
+static inline int i2c_register_driver(struct driver_d *drv)
+{
+ drv->bus = &i2c_bus;
+ return register_driver(drv);
+}
+
#endif /* I2C_I2C_H */
diff --git a/include/image.h b/include/image.h
index 72adf68cbc..219419b12b 100644
--- a/include/image.h
+++ b/include/image.h
@@ -81,6 +81,9 @@
#define IH_ARCH_BLACKFIN 16 /* Blackfin */
#define IH_ARCH_AVR32 17 /* AVR32 */
#define IH_ARCH_LINUX 18 /* Linux */
+#define IH_ARCH_SANDBOX 19 /* Sandbox architecture (test only) */
+#define IH_ARCH_NDS32 20 /* ANDES Technology - NDS32 */
+#define IH_ARCH_OPENRISC 21 /* OpenRISC 1000 */
#if defined(__PPC__)
#define IH_ARCH IH_ARCH_PPC
@@ -98,6 +101,8 @@
#define IH_ARCH IH_ARCH_MICROBLAZE
#elif defined(__nios2__)
#define IH_ARCH IH_ARCH_NIOS2
+#elif defined(__OR1K__)
+#define IH_ARCH IH_ARCH_OPENRISC
#elif defined(__blackfin__)
#define IH_ARCH IH_ARCH_BLACKFIN
#elif defined(__avr32__)
diff --git a/include/image_renderer.h b/include/image_renderer.h
new file mode 100644
index 0000000000..0b686e1686
--- /dev/null
+++ b/include/image_renderer.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2
+ */
+
+#ifndef __IMAGE_RENDER_H__
+#define __IMAGE_RENDER_H__
+
+#include <filetype.h>
+#include <linux/list.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <fb.h>
+
+struct image {
+ void *data;
+ struct image_renderer *ir;
+ int height;
+ int width;
+ int bits_per_pixel;
+};
+
+struct image_renderer {
+ enum filetype type;
+ struct image *(*open)(char *data, int size);
+ void (*close)(struct image *img);
+ int (*renderer)(struct fb_info *info, struct image *img, void* fb,
+ int startx, int starty, void* offscreenbuf);
+
+ /*
+ * do not free the data read from the file
+ * needed by bmp support
+ */
+ int keep_file_data;
+
+ struct list_head list;
+};
+
+#ifdef CONFIG_IMAGE_RENDERER
+int image_renderer_register(struct image_renderer *ir);
+void image_render_unregister(struct image_renderer *ir);
+
+int image_renderer_image(struct fb_info *info, struct image *img, void* fb,
+ int startx, int starty, void* offscreenbuf);
+
+struct image *image_renderer_open(const char* file);
+void image_renderer_close(struct image *img);
+
+#else
+static inline int image_renderer_register(struct image_renderer *ir)
+{
+ return -EINVAL;
+}
+static inline void image_renderer_unregister(struct image_renderer *ir) {}
+
+static inline struct image *image_renderer_open(const char* file)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void image_renderer_close(struct image *img) {}
+
+int image_renderer_image(struct fb_info *info, struct image *img, void* fb,
+ int startx, int starty, void* offscreenbuf);
+#endif
+
+static inline int image_renderer_file(struct fb_info *info, const char* file, void* fb,
+ int startx, int starty, void* offscreenbuf)
+{
+ struct image* img = image_renderer_open(file);
+ int ret;
+
+ if (IS_ERR(img))
+ return PTR_ERR(img);
+
+ ret = image_renderer_image(info, img, fb, startx, starty,
+ offscreenbuf);
+
+ image_renderer_close(img);
+
+ return ret;
+}
+
+#endif /* __IMAGE_RENDERER_H__ */
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
new file mode 100644
index 0000000000..cb3e3bd3b1
--- /dev/null
+++ b/include/linux/amba/bus.h
@@ -0,0 +1,153 @@
+/*
+ * linux/include/amba/bus.h
+ *
+ * This device type deals with ARM PrimeCells and anything else that
+ * presents a proper CID (0xB105F00D) at the end of the I/O register
+ * region or that is derived from a PrimeCell.
+ *
+ * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
+ *
+ * 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.
+ */
+#ifndef ASMARM_AMBA_H
+#define ASMARM_AMBA_H
+
+#include <linux/clk.h>
+#include <driver.h>
+#include <linux/err.h>
+
+#define AMBA_CID 0xb105f00d
+
+/**
+ * struct amba_id - identifies a device on an AMBA bus
+ * @id: The significant bits if the hardware device ID
+ * @mask: Bitmask specifying which bits of the id field are significant when
+ * matching. A driver binds to a device when ((hardware device ID) & mask)
+ * == id.
+ * @data: Private data used by the driver.
+ */
+struct amba_id {
+ unsigned int id;
+ unsigned int mask;
+ void *data;
+};
+
+struct clk;
+
+struct amba_device {
+ struct device_d dev;
+ struct resource res;
+ void __iomem *base;
+ struct clk *pclk;
+ unsigned int periphid;
+};
+
+struct amba_driver {
+ struct driver_d drv;
+ int (*probe)(struct amba_device *, const struct amba_id *);
+ int (*remove)(struct amba_device *);
+ const struct amba_id *id_table;
+};
+
+enum amba_vendor {
+ AMBA_VENDOR_ARM = 0x41,
+ AMBA_VENDOR_ST = 0x80,
+};
+
+extern struct bus_type amba_bustype;
+
+#define to_amba_device(d) container_of(d, struct amba_device, dev)
+
+#define amba_get_drvdata(d) dev_get_drvdata(&d->dev)
+#define amba_set_drvdata(d,p) dev_set_drvdata(&d->dev, p)
+
+int amba_driver_register(struct amba_driver *);
+void amba_driver_unregister(struct amba_driver *);
+struct amba_device *amba_device_alloc(const char *, int id, resource_size_t, size_t);
+void amba_device_put(struct amba_device *);
+int amba_device_add(struct amba_device *);
+int amba_device_register(struct amba_device *, struct resource *);
+
+struct amba_device *
+amba_aphb_device_add(struct device_d *parent, const char *name, int id,
+ resource_size_t base, size_t size,
+ void *pdata, unsigned int periphid);
+
+static inline struct amba_device *
+amba_apb_device_add(struct device_d *parent, const char *name, int id,
+ resource_size_t base, size_t size,
+ void *pdata, unsigned int periphid)
+{
+ return amba_aphb_device_add(parent, name, id, base, size, pdata,
+ periphid);
+}
+
+static inline struct amba_device *
+amba_ahb_device_add(struct device_d *parent, const char *name, int id,
+ resource_size_t base, size_t size,
+ void *pdata, unsigned int periphid)
+{
+ return amba_aphb_device_add(parent, name, id, base, size, pdata,
+ periphid);
+}
+
+
+void amba_device_unregister(struct amba_device *);
+struct amba_device *amba_find_device(const char *, struct device_d *, unsigned int, unsigned int);
+int amba_request_regions(struct amba_device *, const char *);
+void amba_release_regions(struct amba_device *);
+
+static inline void __iomem *amba_get_mem_region(struct amba_device *dev)
+{
+ return dev->base;
+}
+
+#define amba_pclk_enable(d) \
+ (IS_ERR((d)->pclk) ? 0 : clk_enable((d)->pclk))
+
+#define amba_pclk_disable(d) \
+ do { if (!IS_ERR((d)->pclk)) clk_disable((d)->pclk); } while (0)
+
+/* Some drivers don't use the struct amba_device */
+#define AMBA_CONFIG_BITS(a) (((a) >> 24) & 0xff)
+#define AMBA_REV_BITS(a) (((a) >> 20) & 0x0f)
+#define AMBA_MANF_BITS(a) (((a) >> 12) & 0xff)
+#define AMBA_PART_BITS(a) ((a) & 0xfff)
+
+#define amba_config(d) AMBA_CONFIG_BITS((d)->periphid)
+#define amba_rev(d) AMBA_REV_BITS((d)->periphid)
+#define amba_manf(d) AMBA_MANF_BITS((d)->periphid)
+#define amba_part(d) AMBA_PART_BITS((d)->periphid)
+
+#define __AMBA_DEV(busid, data) \
+ { \
+ .init_name = busid, \
+ .platform_data = data, \
+ }
+
+/*
+ * APB devices do not themselves have the ability to address memory,
+ * so DMA masks should be zero (much like USB peripheral devices.)
+ * The DMA controller DMA masks should be used instead (much like
+ * USB host controllers in conventional PCs.)
+ */
+#define AMBA_APB_DEVICE(name, busid, id, base, data) \
+struct amba_device name##_device = { \
+ .dev = __AMBA_DEV(busid, data), \
+ .res = DEFINE_RES_MEM(base, SZ_4K), \
+ .periphid = id, \
+}
+
+/*
+ * AHB devices are DMA capable, so set their DMA masks
+ */
+#define AMBA_AHB_DEVICE(name, busid, id, base, data) \
+struct amba_device name##_device = { \
+ .dev = __AMBA_DEV(busid, data), \
+ .res = DEFINE_RES_MEM(base, SZ_4K), \
+ .periphid = id, \
+}
+
+#endif
diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h
index 7f90b356b5..8ff22d5c8c 100644
--- a/include/linux/amba/serial.h
+++ b/include/linux/amba/serial.h
@@ -29,16 +29,20 @@
#define UART01x_RSR 0x04 /* Receive status register (Read). */
#define UART01x_ECR 0x04 /* Error clear register (Write). */
#define UART010_LCRH 0x08 /* Line control register, high byte. */
+#define ST_UART011_DMAWM 0x08 /* DMA watermark configure register. */
#define UART010_LCRM 0x0C /* Line control register, middle byte. */
+#define ST_UART011_TIMEOUT 0x0C /* Timeout period register. */
#define UART010_LCRL 0x10 /* Line control register, low byte. */
#define UART010_CR 0x14 /* Control register. */
#define UART01x_FR 0x18 /* Flag register (Read only). */
#define UART010_IIR 0x1C /* Interrupt indentification register (Read). */
#define UART010_ICR 0x1C /* Interrupt clear register (Write). */
+#define ST_UART011_LCRH_RX 0x1C /* Rx line control register. */
#define UART01x_ILPR 0x20 /* IrDA low power counter register. */
#define UART011_IBRD 0x24 /* Integer baud rate divisor register. */
#define UART011_FBRD 0x28 /* Fractional baud rate divisor register. */
#define UART011_LCRH 0x2c /* Line control register. */
+#define ST_UART011_LCRH_TX 0x2c /* Tx Line control register. */
#define UART011_CR 0x30 /* Control register. */
#define UART011_IFLS 0x34 /* Interrupt fifo level select. */
#define UART011_IMSC 0x38 /* Interrupt mask. */
@@ -46,6 +50,15 @@
#define UART011_MIS 0x40 /* Masked interrupt status. */
#define UART011_ICR 0x44 /* Interrupt clear register. */
#define UART011_DMACR 0x48 /* DMA control register. */
+#define ST_UART011_XFCR 0x50 /* XON/XOFF control register. */
+#define ST_UART011_XON1 0x54 /* XON1 register. */
+#define ST_UART011_XON2 0x58 /* XON2 register. */
+#define ST_UART011_XOFF1 0x5C /* XON1 register. */
+#define ST_UART011_XOFF2 0x60 /* XON2 register. */
+#define ST_UART011_ITCR 0x80 /* Integration test control register. */
+#define ST_UART011_ITIP 0x84 /* Integration test input register. */
+#define ST_UART011_ABCR 0x100 /* Autobaud control register. */
+#define ST_UART011_ABIMSC 0x15C /* Autobaud interrupt mask/clear register. */
#define UART011_DR_OE (1 << 11)
#define UART011_DR_BE (1 << 10)
@@ -81,6 +94,7 @@
#define UART010_CR_TIE 0x0020
#define UART010_CR_RIE 0x0010
#define UART010_CR_MSIE 0x0008
+#define ST_UART011_CR_OVSFACT 0x0008 /* Oversampling factor */
#define UART01x_CR_IIRLP 0x0004 /* SIR low power mode */
#define UART01x_CR_SIREN 0x0002 /* SIR enable */
#define UART01x_CR_UARTEN 0x0001 /* UART enable */
@@ -96,6 +110,21 @@
#define UART01x_LCRH_PEN 0x02
#define UART01x_LCRH_BRK 0x01
+#define ST_UART011_DMAWM_RX_1 (0 << 3)
+#define ST_UART011_DMAWM_RX_2 (1 << 3)
+#define ST_UART011_DMAWM_RX_4 (2 << 3)
+#define ST_UART011_DMAWM_RX_8 (3 << 3)
+#define ST_UART011_DMAWM_RX_16 (4 << 3)
+#define ST_UART011_DMAWM_RX_32 (5 << 3)
+#define ST_UART011_DMAWM_RX_48 (6 << 3)
+#define ST_UART011_DMAWM_TX_1 0
+#define ST_UART011_DMAWM_TX_2 1
+#define ST_UART011_DMAWM_TX_4 2
+#define ST_UART011_DMAWM_TX_8 3
+#define ST_UART011_DMAWM_TX_16 4
+#define ST_UART011_DMAWM_TX_32 5
+#define ST_UART011_DMAWM_TX_48 6
+
#define UART010_IIR_RTIS 0x08
#define UART010_IIR_TIS 0x04
#define UART010_IIR_RIS 0x02
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
new file mode 100644
index 0000000000..4d83fe019e
--- /dev/null
+++ b/include/linux/ethtool.h
@@ -0,0 +1,114 @@
+/*
+ * ethtool.h: Defines for Linux ethtool.
+ *
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
+ * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ * christopher.leech@intel.com,
+ * scott.feldman@intel.com)
+ * Portions Copyright (C) Sun Microsystems 2008
+ */
+
+#ifndef _LINUX_ETHTOOL_H
+#define _LINUX_ETHTOOL_H
+
+/* Indicates what features are supported by the interface. */
+#define SUPPORTED_10baseT_Half (1 << 0)
+#define SUPPORTED_10baseT_Full (1 << 1)
+#define SUPPORTED_100baseT_Half (1 << 2)
+#define SUPPORTED_100baseT_Full (1 << 3)
+#define SUPPORTED_1000baseT_Half (1 << 4)
+#define SUPPORTED_1000baseT_Full (1 << 5)
+#define SUPPORTED_Autoneg (1 << 6)
+#define SUPPORTED_TP (1 << 7)
+#define SUPPORTED_AUI (1 << 8)
+#define SUPPORTED_MII (1 << 9)
+#define SUPPORTED_FIBRE (1 << 10)
+#define SUPPORTED_BNC (1 << 11)
+#define SUPPORTED_10000baseT_Full (1 << 12)
+#define SUPPORTED_Pause (1 << 13)
+#define SUPPORTED_Asym_Pause (1 << 14)
+#define SUPPORTED_2500baseX_Full (1 << 15)
+#define SUPPORTED_Backplane (1 << 16)
+#define SUPPORTED_1000baseKX_Full (1 << 17)
+#define SUPPORTED_10000baseKX4_Full (1 << 18)
+#define SUPPORTED_10000baseKR_Full (1 << 19)
+#define SUPPORTED_10000baseR_FEC (1 << 20)
+
+/* Indicates what features are advertised by the interface. */
+#define ADVERTISED_10baseT_Half (1 << 0)
+#define ADVERTISED_10baseT_Full (1 << 1)
+#define ADVERTISED_100baseT_Half (1 << 2)
+#define ADVERTISED_100baseT_Full (1 << 3)
+#define ADVERTISED_1000baseT_Half (1 << 4)
+#define ADVERTISED_1000baseT_Full (1 << 5)
+#define ADVERTISED_Autoneg (1 << 6)
+#define ADVERTISED_TP (1 << 7)
+#define ADVERTISED_AUI (1 << 8)
+#define ADVERTISED_MII (1 << 9)
+#define ADVERTISED_FIBRE (1 << 10)
+#define ADVERTISED_BNC (1 << 11)
+#define ADVERTISED_10000baseT_Full (1 << 12)
+#define ADVERTISED_Pause (1 << 13)
+#define ADVERTISED_Asym_Pause (1 << 14)
+#define ADVERTISED_2500baseX_Full (1 << 15)
+#define ADVERTISED_Backplane (1 << 16)
+#define ADVERTISED_1000baseKX_Full (1 << 17)
+#define ADVERTISED_10000baseKX4_Full (1 << 18)
+#define ADVERTISED_10000baseKR_Full (1 << 19)
+#define ADVERTISED_10000baseR_FEC (1 << 20)
+
+/* The following are all involved in forcing a particular link
+ * mode for the device for setting things. When getting the
+ * devices settings, these indicate the current mode and whether
+ * it was foced up into this mode or autonegotiated.
+ */
+
+/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
+#define SPEED_10 10
+#define SPEED_100 100
+#define SPEED_1000 1000
+#define SPEED_2500 2500
+#define SPEED_10000 10000
+
+/* Duplex, half or full. */
+#define DUPLEX_HALF 0x00
+#define DUPLEX_FULL 0x01
+
+/* Which connector port. */
+#define PORT_TP 0x00
+#define PORT_AUI 0x01
+#define PORT_MII 0x02
+#define PORT_FIBRE 0x03
+#define PORT_BNC 0x04
+#define PORT_OTHER 0xff
+
+/* Which transceiver to use. */
+#define XCVR_INTERNAL 0x00
+#define XCVR_EXTERNAL 0x01
+#define XCVR_DUMMY1 0x02
+#define XCVR_DUMMY2 0x03
+#define XCVR_DUMMY3 0x04
+
+/* Enable or disable autonegotiation. If this is set to enable,
+ * the forced link modes above are completely ignored.
+ */
+#define AUTONEG_DISABLE 0x00
+#define AUTONEG_ENABLE 0x01
+
+/* Mode MDI or MDI-X */
+#define ETH_TP_MDI_INVALID 0x00
+#define ETH_TP_MDI 0x01
+#define ETH_TP_MDI_X 0x02
+
+/* Wake-On-Lan options. */
+#define WAKE_PHY (1 << 0)
+#define WAKE_UCAST (1 << 1)
+#define WAKE_MCAST (1 << 2)
+#define WAKE_BCAST (1 << 3)
+#define WAKE_ARP (1 << 4)
+#define WAKE_MAGIC (1 << 5)
+#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */
+
+#endif /* _LINUX_ETHTOOL_H */
diff --git a/include/linux/mii.h b/include/linux/mii.h
index 734517268f..5bac6c229a 100644
--- a/include/linux/mii.h
+++ b/include/linux/mii.h
@@ -8,137 +8,149 @@
#ifndef __LINUX_MII_H__
#define __LINUX_MII_H__
-/* Generic MII registers. */
+#include <linux/types.h>
+#include <linux/ethtool.h>
-#define MII_BMCR 0x00 /* Basic mode control register */
-#define MII_BMSR 0x01 /* Basic mode status register */
-#define MII_PHYSID1 0x02 /* PHYS ID 1 */
-#define MII_PHYSID2 0x03 /* PHYS ID 2 */
-#define MII_ADVERTISE 0x04 /* Advertisement control reg */
-#define MII_LPA 0x05 /* Link partner ability reg */
-#define MII_EXPANSION 0x06 /* Expansion register */
-#define MII_CTRL1000 0x09 /* 1000BASE-T control */
-#define MII_STAT1000 0x0a /* 1000BASE-T status */
-#define MII_ESTATUS 0x0f /* Extended Status */
-#define MII_DCOUNTER 0x12 /* Disconnect counter */
-#define MII_FCSCOUNTER 0x13 /* False carrier counter */
-#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
-#define MII_RERRCOUNTER 0x15 /* Receive error counter */
-#define MII_SREVISION 0x16 /* Silicon revision */
-#define MII_RESV1 0x17 /* Reserved... */
-#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
-#define MII_PHYADDR 0x19 /* PHY address */
-#define MII_RESV2 0x1a /* Reserved... */
-#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
-#define MII_NCONFIG 0x1c /* Network interface config */
+/* Generic MII registers. */
+#define MII_BMCR 0x00 /* Basic mode control register */
+#define MII_BMSR 0x01 /* Basic mode status register */
+#define MII_PHYSID1 0x02 /* PHYS ID 1 */
+#define MII_PHYSID2 0x03 /* PHYS ID 2 */
+#define MII_ADVERTISE 0x04 /* Advertisement control reg */
+#define MII_LPA 0x05 /* Link partner ability reg */
+#define MII_EXPANSION 0x06 /* Expansion register */
+#define MII_CTRL1000 0x09 /* 1000BASE-T control */
+#define MII_STAT1000 0x0a /* 1000BASE-T status */
+#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */
+#define MII_MMD_DATA 0x0e /* MMD Access Data Register */
+#define MII_ESTATUS 0x0f /* Extended Status */
+#define MII_DCOUNTER 0x12 /* Disconnect counter */
+#define MII_FCSCOUNTER 0x13 /* False carrier counter */
+#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */
+#define MII_RERRCOUNTER 0x15 /* Receive error counter */
+#define MII_SREVISION 0x16 /* Silicon revision */
+#define MII_RESV1 0x17 /* Reserved... */
+#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */
+#define MII_PHYADDR 0x19 /* PHY address */
+#define MII_RESV2 0x1a /* Reserved... */
+#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */
+#define MII_NCONFIG 0x1c /* Network interface config */
/* Basic mode control register. */
-#define BMCR_SPEED_MASK 0x2040 /* 10/100/1000 */
-#define BMCR_SPEED10 0x0000 /* Select 10Mbps */
-#define BMCR_RESV 0x003f /* Unused... */
-#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
-#define BMCR_CTST 0x0080 /* Collision test */
-#define BMCR_FULLDPLX 0x0100 /* Full duplex */
-#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
-#define BMCR_ISOLATE 0x0400 /* Disconnect DP83840 from MII */
-#define BMCR_PDOWN 0x0800 /* Powerdown the DP83840 */
-#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
-#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
-#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
-#define BMCR_RESET 0x8000 /* Reset the DP83840 */
+#define BMCR_RESV 0x003f /* Unused... */
+#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */
+#define BMCR_CTST 0x0080 /* Collision test */
+#define BMCR_FULLDPLX 0x0100 /* Full duplex */
+#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */
+#define BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */
+#define BMCR_PDOWN 0x0800 /* Enable low power state */
+#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */
+#define BMCR_SPEED100 0x2000 /* Select 100Mbps */
+#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */
+#define BMCR_RESET 0x8000 /* Reset to default state */
/* Basic mode status register. */
-#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
-#define BMSR_JCD 0x0002 /* Jabber detected */
-#define BMSR_LSTATUS 0x0004 /* Link status */
-#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
-#define BMSR_RFAULT 0x0010 /* Remote fault detected */
-#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
-#define BMSR_RESV 0x00c0 /* Unused... */
-#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
-#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
-#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
-#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
-#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
-#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
-#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
-#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
+#define BMSR_ERCAP 0x0001 /* Ext-reg capability */
+#define BMSR_JCD 0x0002 /* Jabber detected */
+#define BMSR_LSTATUS 0x0004 /* Link status */
+#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */
+#define BMSR_RFAULT 0x0010 /* Remote fault detected */
+#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */
+#define BMSR_RESV 0x00c0 /* Unused... */
+#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */
+#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */
+#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */
+#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */
+#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */
+#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */
+#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */
+#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */
/* Advertisement control register. */
-#define ADVERTISE_SLCT 0x001f /* Selector bits */
-#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
-#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
-#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
-#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
-#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
-#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
-#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
-#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
-#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
-#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
-#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
-#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
-#define ADVERTISE_RESV 0x1000 /* Unused... */
-#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
-#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
-#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
-
-#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
- ADVERTISE_CSMA)
-#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
- ADVERTISE_100HALF | ADVERTISE_100FULL)
+#define ADVERTISE_SLCT 0x001f /* Selector bits */
+#define ADVERTISE_CSMA 0x0001 /* Only selector supported */
+#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
+#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
+#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
+#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
+#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */
+#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */
+#define ADVERTISE_RESV 0x1000 /* Unused... */
+#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */
+#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */
+#define ADVERTISE_NPAGE 0x8000 /* Next page bit */
+
+#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+ ADVERTISE_CSMA)
+#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+ ADVERTISE_100HALF | ADVERTISE_100FULL)
/* Link partner ability register. */
-#define LPA_SLCT 0x001f /* Same as advertise selector */
-#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
-#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
-#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
-#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
-#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
-#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
-#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
-#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
-#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
-#define LPA_PAUSE_CAP 0x0400 /* Can pause */
-#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */
-#define LPA_RESV 0x1000 /* Unused... */
-#define LPA_RFAULT 0x2000 /* Link partner faulted */
-#define LPA_LPACK 0x4000 /* Link partner acked us */
-#define LPA_NPAGE 0x8000 /* Next page bit */
+#define LPA_SLCT 0x001f /* Same as advertise selector */
+#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */
+#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */
+#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */
+#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */
+#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */
+#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */
+#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */
+#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/
+#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */
+#define LPA_PAUSE_CAP 0x0400 /* Can pause */
+#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */
+#define LPA_RESV 0x1000 /* Unused... */
+#define LPA_RFAULT 0x2000 /* Link partner faulted */
+#define LPA_LPACK 0x4000 /* Link partner acked us */
+#define LPA_NPAGE 0x8000 /* Next page bit */
#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL)
#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4)
/* Expansion register for auto-negotiation. */
-#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */
-#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */
-#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */
-#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */
-#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
-#define EXPANSION_RESV 0xffe0 /* Unused... */
+#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */
+#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */
+#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */
+#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */
+#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */
+#define EXPANSION_RESV 0xffe0 /* Unused... */
-#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
-#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
+#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */
+#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */
/* N-way test register. */
-#define NWAYTEST_RESV1 0x00ff /* Unused... */
-#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
-#define NWAYTEST_RESV2 0xfe00 /* Unused... */
+#define NWAYTEST_RESV1 0x00ff /* Unused... */
+#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */
+#define NWAYTEST_RESV2 0xfe00 /* Unused... */
/* 1000BASE-T Control register */
-#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
-#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
+#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
+#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
+#define CTL1000_AS_MASTER 0x0800
+#define CTL1000_ENABLE_MASTER 0x1000
/* 1000BASE-T Status register */
-#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
-#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
-#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
-#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */
+#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
+#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
+#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
+#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */
/* Flow control flags */
#define FLOW_CTRL_TX 0x01
#define FLOW_CTRL_RX 0x02
+/* MMD Access Control register fields */
+#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
+#define MII_MMD_CTRL_ADDR 0x0000 /* Address */
+#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
+#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
+#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
+
+
/**
* mii_nway_result
* @negotiated: value of MII ANAR and'd with ANLPAR
@@ -191,6 +203,205 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock,
}
/**
+ * ethtool_adv_to_mii_adv_t
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_ADVERTISE register.
+ */
+static inline u32 ethtool_adv_to_mii_adv_t(u32 ethadv)
+{
+ u32 result = 0;
+
+ if (ethadv & ADVERTISED_10baseT_Half)
+ result |= ADVERTISE_10HALF;
+ if (ethadv & ADVERTISED_10baseT_Full)
+ result |= ADVERTISE_10FULL;
+ if (ethadv & ADVERTISED_100baseT_Half)
+ result |= ADVERTISE_100HALF;
+ if (ethadv & ADVERTISED_100baseT_Full)
+ result |= ADVERTISE_100FULL;
+ if (ethadv & ADVERTISED_Pause)
+ result |= ADVERTISE_PAUSE_CAP;
+ if (ethadv & ADVERTISED_Asym_Pause)
+ result |= ADVERTISE_PAUSE_ASYM;
+
+ return result;
+}
+
+/**
+ * mii_adv_to_ethtool_adv_t
+ * @adv: value of the MII_ADVERTISE register
+ *
+ * A small helper function that translates MII_ADVERTISE bits
+ * to ethtool advertisement settings.
+ */
+static inline u32 mii_adv_to_ethtool_adv_t(u32 adv)
+{
+ u32 result = 0;
+
+ if (adv & ADVERTISE_10HALF)
+ result |= ADVERTISED_10baseT_Half;
+ if (adv & ADVERTISE_10FULL)
+ result |= ADVERTISED_10baseT_Full;
+ if (adv & ADVERTISE_100HALF)
+ result |= ADVERTISED_100baseT_Half;
+ if (adv & ADVERTISE_100FULL)
+ result |= ADVERTISED_100baseT_Full;
+ if (adv & ADVERTISE_PAUSE_CAP)
+ result |= ADVERTISED_Pause;
+ if (adv & ADVERTISE_PAUSE_ASYM)
+ result |= ADVERTISED_Asym_Pause;
+
+ return result;
+}
+
+/**
+ * ethtool_adv_to_mii_ctrl1000_t
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_CTRL1000 register when in 1000T mode.
+ */
+static inline u32 ethtool_adv_to_mii_ctrl1000_t(u32 ethadv)
+{
+ u32 result = 0;
+
+ if (ethadv & ADVERTISED_1000baseT_Half)
+ result |= ADVERTISE_1000HALF;
+ if (ethadv & ADVERTISED_1000baseT_Full)
+ result |= ADVERTISE_1000FULL;
+
+ return result;
+}
+
+/**
+ * mii_ctrl1000_to_ethtool_adv_t
+ * @adv: value of the MII_CTRL1000 register
+ *
+ * A small helper function that translates MII_CTRL1000
+ * bits, when in 1000Base-T mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_ctrl1000_to_ethtool_adv_t(u32 adv)
+{
+ u32 result = 0;
+
+ if (adv & ADVERTISE_1000HALF)
+ result |= ADVERTISED_1000baseT_Half;
+ if (adv & ADVERTISE_1000FULL)
+ result |= ADVERTISED_1000baseT_Full;
+
+ return result;
+}
+
+/**
+ * mii_lpa_to_ethtool_lpa_t
+ * @adv: value of the MII_LPA register
+ *
+ * A small helper function that translates MII_LPA
+ * bits, when in 1000Base-T mode, to ethtool
+ * LP advertisement settings.
+ */
+static inline u32 mii_lpa_to_ethtool_lpa_t(u32 lpa)
+{
+ u32 result = 0;
+
+ if (lpa & LPA_LPACK)
+ result |= ADVERTISED_Autoneg;
+
+ return result | mii_adv_to_ethtool_adv_t(lpa);
+}
+
+/**
+ * mii_stat1000_to_ethtool_lpa_t
+ * @adv: value of the MII_STAT1000 register
+ *
+ * A small helper function that translates MII_STAT1000
+ * bits, when in 1000Base-T mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_stat1000_to_ethtool_lpa_t(u32 lpa)
+{
+ u32 result = 0;
+
+ if (lpa & LPA_1000HALF)
+ result |= ADVERTISED_1000baseT_Half;
+ if (lpa & LPA_1000FULL)
+ result |= ADVERTISED_1000baseT_Full;
+
+ return result;
+}
+
+/**
+ * ethtool_adv_to_mii_adv_x
+ * @ethadv: the ethtool advertisement settings
+ *
+ * A small helper function that translates ethtool advertisement
+ * settings to phy autonegotiation advertisements for the
+ * MII_CTRL1000 register when in 1000Base-X mode.
+ */
+static inline u32 ethtool_adv_to_mii_adv_x(u32 ethadv)
+{
+ u32 result = 0;
+
+ if (ethadv & ADVERTISED_1000baseT_Half)
+ result |= ADVERTISE_1000XHALF;
+ if (ethadv & ADVERTISED_1000baseT_Full)
+ result |= ADVERTISE_1000XFULL;
+ if (ethadv & ADVERTISED_Pause)
+ result |= ADVERTISE_1000XPAUSE;
+ if (ethadv & ADVERTISED_Asym_Pause)
+ result |= ADVERTISE_1000XPSE_ASYM;
+
+ return result;
+}
+
+/**
+ * mii_adv_to_ethtool_adv_x
+ * @adv: value of the MII_CTRL1000 register
+ *
+ * A small helper function that translates MII_CTRL1000
+ * bits, when in 1000Base-X mode, to ethtool
+ * advertisement settings.
+ */
+static inline u32 mii_adv_to_ethtool_adv_x(u32 adv)
+{
+ u32 result = 0;
+
+ if (adv & ADVERTISE_1000XHALF)
+ result |= ADVERTISED_1000baseT_Half;
+ if (adv & ADVERTISE_1000XFULL)
+ result |= ADVERTISED_1000baseT_Full;
+ if (adv & ADVERTISE_1000XPAUSE)
+ result |= ADVERTISED_Pause;
+ if (adv & ADVERTISE_1000XPSE_ASYM)
+ result |= ADVERTISED_Asym_Pause;
+
+ return result;
+}
+
+/**
+ * mii_lpa_to_ethtool_lpa_x
+ * @adv: value of the MII_LPA register
+ *
+ * A small helper function that translates MII_LPA
+ * bits, when in 1000Base-X mode, to ethtool
+ * LP advertisement settings.
+ */
+static inline u32 mii_lpa_to_ethtool_lpa_x(u32 lpa)
+{
+ u32 result = 0;
+
+ if (lpa & LPA_LPACK)
+ result |= ADVERTISED_Autoneg;
+
+ return result | mii_adv_to_ethtool_adv_x(lpa);
+}
+
+/**
* mii_advertise_flowctrl - get flow control advertisement flags
* @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both)
*/
diff --git a/include/linux/phy.h b/include/linux/phy.h
new file mode 100644
index 0000000000..76f9edb237
--- /dev/null
+++ b/include/linux/phy.h
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2009-2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * Author: Andy Fleming
+ *
+ * Copyright (c) 2004 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __PHY_H
+#define __PHY_H
+
+#include <linux/list.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+
+#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
+ SUPPORTED_10baseT_Full | \
+ SUPPORTED_100baseT_Half | \
+ SUPPORTED_100baseT_Full | \
+ SUPPORTED_Autoneg | \
+ SUPPORTED_TP | \
+ SUPPORTED_MII)
+
+#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \
+ SUPPORTED_1000baseT_Half | \
+ SUPPORTED_1000baseT_Full)
+
+/* Interface Mode definitions */
+typedef enum {
+ PHY_INTERFACE_MODE_NA,
+ PHY_INTERFACE_MODE_MII,
+ PHY_INTERFACE_MODE_GMII,
+ PHY_INTERFACE_MODE_SGMII,
+ PHY_INTERFACE_MODE_TBI,
+ PHY_INTERFACE_MODE_RMII,
+ PHY_INTERFACE_MODE_RGMII,
+ PHY_INTERFACE_MODE_RGMII_ID,
+ PHY_INTERFACE_MODE_RGMII_RXID,
+ PHY_INTERFACE_MODE_RGMII_TXID,
+ PHY_INTERFACE_MODE_RTBI,
+ PHY_INTERFACE_MODE_SMII,
+} phy_interface_t;
+
+#define PHY_INIT_TIMEOUT 100000
+#define PHY_FORCE_TIMEOUT 10
+#define PHY_AN_TIMEOUT 10
+
+#define PHY_MAX_ADDR 32
+
+/*
+ * Need to be a little smaller than phydev->dev.bus_id to leave room
+ * for the ":%02x"
+ */
+#define MII_BUS_ID_SIZE (20 - 3)
+
+#define PHYLIB_FORCE_10 (1 << 0)
+#define PHYLIB_FORCE_LINK (1 << 1)
+
+#define PHYLIB_CAPABLE_1000M (1 << 0)
+
+/*
+ * The Bus class for PHYs. Devices which provide access to
+ * PHYs should register using this structure
+ */
+struct mii_bus {
+ void *priv;
+ int (*read)(struct mii_bus *bus, int phy_id, int regnum);
+ int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val);
+ int (*reset)(struct mii_bus *bus);
+
+ struct device_d *parent;
+
+ struct device_d dev;
+
+ /* list of all PHYs on bus */
+ struct phy_device *phy_map[PHY_MAX_ADDR];
+
+ /* PHY addresses to be ignored when probing */
+ u32 phy_mask;
+};
+#define to_mii_bus(d) container_of(d, struct mii_bus, dev)
+
+int mdiobus_register(struct mii_bus *bus);
+void mdiobus_unregister(struct mii_bus *bus);
+struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr);
+
+/**
+ * mdiobus_read - Convenience function for reading a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to read
+ */
+static inline int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum)
+{
+ return bus->read(bus, addr, regnum);
+}
+
+/**
+ * mdiobus_write - Convenience function for writing a given MII mgmt register
+ * @bus: the mii_bus struct
+ * @addr: the phy address
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ */
+static inline int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val)
+{
+ return bus->write(bus, addr, regnum, val);
+}
+
+/* phy_device: An instance of a PHY
+ *
+ * bus: Pointer to the bus this PHY is on
+ * dev: driver model device structure for this PHY
+ * phy_id: UID for this device found during discovery
+ * dev_flags: Device-specific flags used by the PHY driver.
+ * addr: Bus address of PHY
+ * attached_dev: The attached enet driver's device instance ptr
+ *
+ * speed, duplex, pause, supported, advertising, and
+ * autoneg are used like in mii_if_info
+ */
+struct phy_device {
+ struct mii_bus *bus;
+
+ struct device_d dev;
+
+ u32 phy_id;
+
+ u32 dev_flags;
+
+ phy_interface_t interface;
+
+ /* Bus address of the PHY (0-31) */
+ int addr;
+
+ /*
+ * forced speed & duplex (no autoneg)
+ * partner speed & duplex & pause (autoneg)
+ */
+ int speed;
+ int duplex;
+ int pause;
+ int asym_pause;
+
+ /* The most recently read link state */
+ int link;
+
+ /* Union of PHY and Attached devices' supported modes */
+ /* See mii.h for more info */
+ u32 supported;
+ u32 advertising;
+
+ int autoneg;
+
+
+ /* private data pointer */
+ /* For use by PHYs to maintain extra state */
+ void *priv;
+
+ struct eth_device *attached_dev;
+ void (*adjust_link)(struct eth_device *dev);
+
+ struct cdev cdev;
+};
+#define to_phy_device(d) container_of(d, struct phy_device, dev)
+
+/* struct phy_driver: Driver structure for a particular PHY type
+ *
+ * phy_id: The result of reading the UID registers of this PHY
+ * type, and ANDing them with the phy_id_mask. This driver
+ * only works for PHYs with IDs which match this field
+ * phy_id_mask: Defines the important bits of the phy_id
+ * features: A list of features (speed, duplex, etc) supported
+ * by this PHY
+ *
+ * The drivers must implement config_aneg and read_status. All
+ * other functions are optional. Note that none of these
+ * functions should be called from interrupt time. The goal is
+ * for the bus read/write functions to be able to block when the
+ * bus transaction is happening, and be freed up by an interrupt
+ * (The MPC85xx has this ability, though it is not currently
+ * supported in the driver).
+ */
+struct phy_driver {
+ u32 phy_id;
+ unsigned int phy_id_mask;
+ u32 features;
+
+ /*
+ * Called to initialize the PHY,
+ * including after a reset
+ */
+ int (*config_init)(struct phy_device *phydev);
+
+ /*
+ * Called during discovery. Used to set
+ * up device-specific structures, if any
+ */
+ int (*probe)(struct phy_device *phydev);
+
+ /*
+ * Configures the advertisement and resets
+ * autonegotiation if phydev->autoneg is on,
+ * forces the speed to the current settings in phydev
+ * if phydev->autoneg is off
+ */
+ int (*config_aneg)(struct phy_device *phydev);
+
+ /* Determines the negotiated speed and duplex */
+ int (*read_status)(struct phy_device *phydev);
+
+ /* Clears up any memory if needed */
+ void (*remove)(struct phy_device *phydev);
+
+ struct driver_d drv;
+};
+#define to_phy_driver(d) container_of(d, struct phy_driver, drv)
+
+#define PHY_ANY_ID "MATCH ANY PHY"
+#define PHY_ANY_UID 0xffffffff
+
+int phy_driver_register(struct phy_driver *drv);
+struct phy_device *get_phy_device(struct mii_bus *bus, int addr);
+int phy_init(void);
+
+/**
+ * phy_read - Convenience function for reading a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to read
+ */
+static inline int phy_read(struct phy_device *phydev, u32 regnum)
+{
+ return mdiobus_read(phydev->bus, phydev->addr, regnum);
+}
+
+/**
+ * phy_write - Convenience function for writing a given PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to write
+ * @val: value to write to @regnum
+ */
+static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val)
+{
+ return mdiobus_write(phydev->bus, phydev->addr, regnum, val);
+}
+
+int phy_device_connect(struct eth_device *dev, struct mii_bus *bus, int addr,
+ void (*adjust_link) (struct eth_device *edev),
+ u32 flags, phy_interface_t interface);
+
+int phy_update_status(struct phy_device *phydev);
+
+/* Generic PHY support and helper functions */
+int genphy_restart_aneg(struct phy_device *phydev);
+int genphy_config_aneg(struct phy_device *phydev);
+int genphy_update_link(struct phy_device *phydev);
+int genphy_read_status(struct phy_device *phydev);
+int genphy_config_advert(struct phy_device *phydev);
+int genphy_setup_forced(struct phy_device *phydev);
+int get_phy_id(struct mii_bus *bus, int addr, u32 *phy_id);
+
+extern struct bus_type mdio_bus_type;
+#endif /* __PHYDEV_H__ */
diff --git a/include/miidev.h b/include/miidev.h
deleted file mode 100644
index 663727a535..0000000000
--- a/include/miidev.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * (C) Copyright 2001
- * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com.
- *
- * (C) Copyright 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.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.
- *
- */
-#ifndef __MIIDEV_H__
-#define __MIIDEV_H__
-
-#include <driver.h>
-#include <linux/mii.h>
-
-#define MIIDEV_FORCE_10 (1 << 0)
-#define MIIDEV_FORCE_LINK (1 << 1)
-
-#define MIIDEV_CAPABLE_1000M (1 << 0)
-
-struct mii_device {
- struct device_d dev;
- struct device_d *parent;
-
- int address; /* The address the phy has on the bus */
- int (*read) (struct mii_device *dev, int addr, int reg);
- int (*write) (struct mii_device *dev, int addr, int reg, int value);
-
- int flags;
- int capabilities;
-
- struct eth_device *edev;
- struct cdev cdev;
- struct list_head list;
-};
-
-int mii_register(struct mii_device *dev);
-void mii_unregister(struct mii_device *mdev);
-int miidev_restart_aneg(struct mii_device *mdev);
-int miidev_wait_aneg(struct mii_device *mdev);
-int miidev_get_status(struct mii_device *mdev);
-#define MIIDEV_STATUS_IS_UP (1 << 0)
-#define MIIDEV_STATUS_IS_FULL_DUPLEX (1 << 1)
-#define MIIDEV_STATUS_IS_10MBIT (1 << 2)
-#define MIIDEV_STATUS_IS_100MBIT (1 << 3)
-#define MIIDEV_STATUS_IS_1000MBIT (1 << 4)
-int miidev_print_status(struct mii_device *mdev);
-
-static int inline mii_write(struct mii_device *dev, int addr, int reg, int value)
-{
- return dev->write(dev, addr, reg, value);
-}
-
-static int inline mii_read(struct mii_device *dev, int addr, int reg)
-{
- return dev->read(dev, addr, reg);
-}
-
-struct mii_device *mii_open(const char *name);
-void mii_close(struct mii_device *mdev);
-
-#endif /* __MIIDEV_H__ */
diff --git a/include/net.h b/include/net.h
index 9152943812..e4f6f86ad0 100644
--- a/include/net.h
+++ b/include/net.h
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <clock.h>
#include <led.h>
+#include <linux/phy.h>
#include <asm/byteorder.h> /* for nton* / ntoh* stuff */
/* How often do we retry to send packages */
@@ -44,6 +45,9 @@ struct eth_device {
struct eth_device *next;
void *priv;
+ /* phy device may attach itself for hardware timestamping */
+ struct phy_device *phydev;
+
struct device_d dev;
struct device_d *parent;
@@ -55,10 +59,8 @@ struct eth_device {
int eth_register(struct eth_device* dev); /* Register network device */
void eth_unregister(struct eth_device* dev); /* Unregister network device */
-int eth_open(void); /* open the device */
int eth_send(void *packet, int length); /* Send a packet */
int eth_rx(void); /* Check for received packets */
-void eth_halt(void); /* stop SCC */
/* associate a MAC address to a ethernet device. Should be called by
* board code for boards which store their MAC address at some unusual
diff --git a/include/net/davinci_emac.h b/include/net/davinci_emac.h
new file mode 100644
index 0000000000..caead1fecf
--- /dev/null
+++ b/include/net/davinci_emac.h
@@ -0,0 +1,10 @@
+#ifndef __NET_DAVINCI_EMAC_H__
+#define __NET_DAVINCI_EMAC_H__
+
+struct davinci_emac_platform_data {
+ int phy_addr;
+ bool force_link;
+ bool interface_rmii;
+};
+
+#endif /* __NET_DAVINCI_EMAC_H__ */
diff --git a/include/of.h b/include/of.h
index 609b3b587b..7b6a23ad71 100644
--- a/include/of.h
+++ b/include/of.h
@@ -2,6 +2,8 @@
#define __OF_H
#include <fdt.h>
+#include <errno.h>
+#include <asm/byteorder.h>
extern struct fdt_header *barebox_fdt;
@@ -19,4 +21,115 @@ void do_fixup_by_path_u32(struct fdt_header *fdt, const char *path, const char *
u32 val, int create);
int fdt_get_path_or_create(struct fdt_header *fdt, const char *path);
+#define OF_BAD_ADDR ((u64)-1)
+
+typedef u32 phandle;
+
+struct property {
+ char *name;
+ int length;
+ void *value;
+ struct list_head list;
+};
+
+struct device_node {
+ char *name;
+ char *full_name;
+
+ struct list_head properties;
+ struct device_node *parent;
+ struct list_head children;
+ struct list_head parent_list;
+ struct list_head list;
+ struct resource *resource;
+ struct device_d *device;
+ struct list_head phandles;
+ phandle phandle;
+};
+
+struct of_device_id {
+ char *compatible;
+ unsigned long data;
+};
+
+struct driver_d;
+
+int of_match(struct device_d *dev, struct driver_d *drv);
+
+struct property *of_find_property(const struct device_node *node, const char *name);
+
+struct device_node *of_find_node_by_path(const char *path);
+
+struct fdt_header *fdt_get_tree(void);
+
+#define device_node_for_nach_child(node, child) \
+ list_for_each_entry(child, &node->children, parent_list)
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline u64 of_read_number(const __be32 *cell, int size)
+{
+ u64 r = 0;
+ while (size--)
+ r = (r << 32) | be32_to_cpu(*(cell++));
+ return r;
+}
+
+int of_property_read_u32_array(const struct device_node *np,
+ const char *propname, u32 *out_values,
+ size_t sz);
+
+static inline int of_property_read_u32(const struct device_node *np,
+ const char *propname,
+ u32 *out_value)
+{
+ return of_property_read_u32_array(np, propname, out_value, 1);
+}
+
+const void *of_get_property(const struct device_node *np, const char *name,
+ int *lenp);
+
+int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
+ const char *cells_name, int index,
+ struct device_node **out_node,
+ const void **out_args);
+
+int of_get_named_gpio(struct device_node *np,
+ const char *propname, int index);
+
+struct device_node *of_find_node_by_phandle(phandle phandle);
+void of_print_property(const void *data, int len);
+
+int of_machine_is_compatible(const char *compat);
+
+#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1
+
+void of_print_nodes(struct device_node *node, int indent);
+int of_probe(void);
+int of_parse_dtb(struct fdt_header *fdt);
+
+#ifdef CONFIG_OFDEVICE
+int of_parse_partitions(const char *cdevname,
+ struct device_node *node);
+
+struct device_node *of_get_root_node(void);
+int of_alias_get_id(struct device_node *np, const char *stem);
+#else
+static inline int of_parse_partitions(const char *cdevname,
+ struct device_node *node)
+{
+ return -EINVAL;
+}
+
+static inline struct device_node *of_get_root_node(void)
+{
+ return NULL;
+}
+
+static inline int of_alias_get_id(struct device_node *np, const char *stem)
+{
+ return -ENOENT;
+}
+#endif
+
#endif /* __OF_H */
diff --git a/include/spi/spi.h b/include/spi/spi.h
index 9d01d068da..1773ca22e5 100644
--- a/include/spi/spi.h
+++ b/include/spi/spi.h
@@ -17,6 +17,7 @@ struct spi_board_info {
u8 mode;
u8 bits_per_word;
void *platform_data;
+ struct device_node *device_node;
};
/**
@@ -163,6 +164,8 @@ struct spi_master {
/* called on release() to free memory provided by spi_master */
void (*cleanup)(struct spi_device *spi);
+
+ struct list_head list;
};
/*---------------------------------------------------------------------------*/
@@ -427,4 +430,14 @@ static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd)
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+extern struct bus_type spi_bus;
+
+static inline int spi_register_driver(struct driver_d *drv)
+{
+ drv->bus = &spi_bus;
+ return register_driver(drv);
+}
+
+void spi_of_register_slaves(struct spi_master *master, struct device_node *node);
+
#endif /* __INCLUDE_SPI_H */
diff --git a/include/usb/usbnet.h b/include/usb/usbnet.h
index 4087479a1f..386c2164bd 100644
--- a/include/usb/usbnet.h
+++ b/include/usb/usbnet.h
@@ -20,7 +20,7 @@
#define __LINUX_USB_USBNET_H
#include <net.h>
-#include <miidev.h>
+#include <linux/phy.h>
/* interface from usbnet core to each USB networking link we handle */
struct usbnet {
@@ -37,7 +37,8 @@ struct usbnet {
/* protocol/interface state */
struct eth_device edev;
- struct mii_device miidev;
+ struct mii_bus miibus;
+ int phy_addr;
int msg_enable;
unsigned long data [5];
diff --git a/lib/Kconfig b/lib/Kconfig
index 32634dfbc1..8b73733735 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -38,4 +38,40 @@ config BITREV
config QSORT
bool
+config IMAGE_RENDERER
+ bool
+ depends on VIDEO
+ select FILETYPE
+
+if IMAGE_RENDERER
+
+config BMP
+ bool "bmp"
+
+config PNG
+ bool "png"
+ select ZLIB
+
+if PNG
+
+choice
+ prompt "PNG Lib"
+
+config LODEPNG
+ bool "lodePNG"
+ help
+ This PNG library supports most PNG formats.
+
+config PICOPNG
+ bool "picoPNG"
+ help
+ This PNG library only supports RGBA PNG8 but is much smaller
+ in binary size than lodepng.
+
+endchoice
+
+endif
+
+endif
+
endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 4e6b1ee90d..7bce0e58c4 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -34,3 +34,8 @@ obj-$(CONFIG_UNCOMPRESS) += uncompress.o
obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
+obj-$(CONFIG_BMP) += bmp.o
+obj-$(CONFIG_IMAGE_RENDERER) += image_renderer.o graphic_utils.o
+obj-$(CONFIG_PNG) += png.o
+obj-$(CONFIG_LODEPNG) += png_lode.o lodepng.o
+obj-$(CONFIG_PICOPNG) += png_pico.o picopng.o
diff --git a/lib/bmp.c b/lib/bmp.c
new file mode 100644
index 0000000000..f5c19616d7
--- /dev/null
+++ b/lib/bmp.c
@@ -0,0 +1,134 @@
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fb.h>
+#include "bmp_layout.h"
+#include <asm/byteorder.h>
+#include <graphic_utils.h>
+#include <init.h>
+#include <image_renderer.h>
+
+struct image *bmp_open(char *inbuf, int insize)
+{
+ struct image *img = calloc(1, sizeof(struct image));
+ struct bmp_image *bmp = (struct bmp_image*)inbuf;
+
+ if (!img) {
+ free(bmp);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ img->data = inbuf;
+ img->height = le32_to_cpu(bmp->header.height);;
+ img->width = le32_to_cpu(bmp->header.width);;
+ img->bits_per_pixel = le16_to_cpu(bmp->header.bit_count);
+
+ pr_debug("bmp: %d x %d x %d data@0x%p\n", img->width, img->height,
+ img->bit_per_pixel, img->data);
+
+ return img;
+}
+
+void bmp_close(struct image *img)
+{
+ free(img->data);
+}
+
+static int bmp_renderer(struct fb_info *info, struct image *img, void* fb,
+ int startx, int starty, void* offscreenbuf)
+{
+ struct bmp_image *bmp = img->data;
+ int width, height;
+ int bits_per_pixel, fbsize;
+ void *adr, *buf;
+ char *image;
+ int xres, yres;
+
+ xres = info->xres;
+ yres = info->yres;
+
+ if (startx < 0) {
+ startx = (xres - img->width) / 2;
+ if (startx < 0)
+ startx = 0;
+ }
+
+ if (starty < 0) {
+ starty = (yres - img->height) / 2;
+ if (starty < 0)
+ starty = 0;
+ }
+
+ width = min(img->width, xres - startx);
+ height = min(img->height, yres - starty);
+
+ bits_per_pixel = img->bits_per_pixel;
+ fbsize = xres * yres * (info->bits_per_pixel >> 3);
+
+ buf = offscreenbuf ? offscreenbuf : fb;
+
+ if (bits_per_pixel == 8) {
+ int x, y;
+ struct bmp_color_table_entry *color_table = bmp->color_table;
+
+ for (y = 0; y < height; y++) {
+ image = (char *)bmp +
+ le32_to_cpu(bmp->header.data_offset);
+ image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3);
+ adr = buf + ((y + starty) * xres + startx) *
+ (info->bits_per_pixel >> 3);
+ for (x = 0; x < width; x++) {
+ int pixel;
+
+ pixel = *image;
+
+ set_rgb_pixel(info, adr, color_table[pixel].red,
+ color_table[pixel].green,
+ color_table[pixel].blue);
+ adr += info->bits_per_pixel >> 3;
+
+ image += bits_per_pixel >> 3;
+ }
+ }
+ } else if (bits_per_pixel == 24) {
+ int x, y;
+
+ for (y = 0; y < height; y++) {
+ image = (char *)bmp +
+ le32_to_cpu(bmp->header.data_offset);
+ image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3);
+ adr = buf + ((y + starty) * xres + startx) *
+ (info->bits_per_pixel >> 3);
+ for (x = 0; x < width; x++) {
+ char *pixel;
+
+ pixel = image;
+
+ set_rgb_pixel(info, adr, pixel[2], pixel[1],
+ pixel[0]);
+ adr += info->bits_per_pixel >> 3;
+
+ image += bits_per_pixel >> 3;
+ }
+ }
+ } else
+ printf("bmp: illegal bits per pixel value: %d\n", bits_per_pixel);
+
+ if (offscreenbuf)
+ memcpy(fb, offscreenbuf, fbsize);
+
+ return img->height;
+}
+
+static struct image_renderer bmp = {
+ .type = filetype_bmp,
+ .open = bmp_open,
+ .close = bmp_close,
+ .renderer = bmp_renderer,
+};
+
+static int bmp_init(void)
+{
+ return image_renderer_register(&bmp);
+}
+fs_initcall(bmp_init);
diff --git a/include/bmp_layout.h b/lib/bmp_layout.h
index 97cc05e25c..d7db537539 100644
--- a/include/bmp_layout.h
+++ b/lib/bmp_layout.h
@@ -70,4 +70,15 @@ struct bmp_image {
#define BMP_BI_RLE8 1
#define BMP_BI_RLE4 2
+#ifdef CONFIG_BMP
+int bmp_render_file(struct fb_info *info, const char* bmpfile, void* fb,
+ int startx, int starty, int xres, int yres, void* offscreenbuf);
+#else
+static inline int bmp_render_file(struct fb_info *info, const char* bmpfile, void* fb,
+ int startx, int starty, int xres, int yres, void* offscreenbuf)
+{
+ return -ENOSYS;
+}
+#endif
+
#endif /* _BMP_H_ */
diff --git a/lib/graphic_utils.c b/lib/graphic_utils.c
new file mode 100644
index 0000000000..a435bdd1e3
--- /dev/null
+++ b/lib/graphic_utils.c
@@ -0,0 +1,191 @@
+#include <common.h>
+#include <fb.h>
+#include <graphic_utils.h>
+
+static u32 get_pixel(struct fb_info *info, u32 color)
+{
+ u32 px;
+ u8 t = (color >> 24) & 0xff;
+ u8 r = (color >> 16) & 0xff;
+ u8 g = (color >> 8 ) & 0xff;
+ u8 b = (color >> 0 ) & 0xff;
+
+ if (info->grayscale) {
+ px = (r | g | b) ? 0xffffffff : 0x0;
+ return px;
+ }
+
+ px = (t >> (8 - info->transp.length)) << info->transp.offset |
+ (r >> (8 - info->red.length)) << info->red.offset |
+ (g >> (8 - info->green.length)) << info->green.offset |
+ (b >> (8 - info->blue.length)) << info->blue.offset;
+
+ return px;
+}
+
+static void memsetw(void *s, u16 c, size_t n)
+{
+ size_t i;
+ u16* tmp = s;
+
+ for (i = 0; i < n; i++)
+ *tmp++ = c;
+}
+
+static void memsetl(void *s, u32 c, size_t n)
+{
+ size_t i;
+ u32* tmp = s;
+
+ for (i = 0; i < n; i++)
+ *tmp++ = c;
+}
+
+void memset_pixel(struct fb_info *info, void* buf, u32 color, size_t size)
+{
+ u32 px;
+ u8 *screen = buf;
+
+ px = get_pixel(info, color);
+
+ switch (info->bits_per_pixel) {
+ case 8:
+ memset(screen, (uint8_t)px, size);
+ break;
+ case 16:
+ memsetw(screen, (uint16_t)px, size);
+ break;
+ case 32:
+ case 24:
+ memsetl(screen, px, size);
+ break;
+ }
+}
+
+static void get_rgb_pixel(struct fb_info *info, void *adr, u8 *r ,u8 *g, u8 *b)
+{
+ u32 px;
+ u32 rmask, gmask, bmask;
+
+ switch (info->bits_per_pixel) {
+ case 16:
+ px = *(u16 *)adr;
+ break;
+ case 32:
+ px = *(u32 *)adr;
+ break;
+ case 8:
+ default:
+ return;
+ }
+
+ rmask = (0xff >> (8 - info->blue.length)) << info->blue.offset |
+ (0xff >> (8 - info->green.length)) << info->green.offset;
+
+ gmask = (0xff >> (8 - info->red.length)) << info->red.offset |
+ (0xff >> (8 - info->blue.length)) << info->blue.offset;
+
+ bmask = (0xff >> (8 - info->red.length)) << info->red.offset |
+ (0xff >> (8 - info->green.length)) << info->green.offset;
+
+ *r = ((px & ~rmask) >> info->red.offset) << (8 - info->red.length);
+ *g = ((px & ~gmask) >> info->green.offset) << (8 - info->green.length);
+ *b = ((px & ~bmask) >> info->blue.offset) << (8 - info->blue.length);
+}
+
+void set_pixel(struct fb_info *info, void *adr, u32 px)
+{
+ switch (info->bits_per_pixel) {
+ case 8:
+ break;
+ case 16:
+ *(u16 *)adr = px;
+ break;
+ case 32:
+ *(u32 *)adr = px;
+ break;
+ }
+}
+
+void set_rgb_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b)
+{
+ u32 px;
+
+ px = (r >> (8 - info->red.length)) << info->red.offset |
+ (g >> (8 - info->green.length)) << info->green.offset |
+ (b >> (8 - info->blue.length)) << info->blue.offset;
+
+ set_pixel(info, adr, px);
+}
+
+static u8 alpha_mux(int s, int d, int a)
+{
+ return (d * a + s * (255 - a)) >> 8;
+}
+
+void set_rgba_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b, u8 a)
+{
+ u32 px = 0x0;
+
+ if (!a)
+ return;
+
+ if (a != 0xff) {
+ if (info->transp.length) {
+ px |= (a >> (8 - info->transp.length)) << info->transp.offset;
+ } else {
+ u8 sr = 0;
+ u8 sg = 0;
+ u8 sb = 0;
+
+ get_rgb_pixel(info, adr, &sr, &sg, &sb);
+
+ r = alpha_mux(sr, r, a);
+ g = alpha_mux(sg, g, a);
+ b = alpha_mux(sb, b, a);
+
+ set_rgb_pixel(info, adr, r, g, b);
+
+ return;
+ }
+ }
+
+ px |= (r >> (8 - info->red.length)) << info->red.offset |
+ (g >> (8 - info->green.length)) << info->green.offset |
+ (b >> (8 - info->blue.length)) << info->blue.offset;
+
+ set_pixel(info, adr, px);
+}
+
+void rgba_blend(struct fb_info *info, void *image, void* buf, int height,
+ int width, int startx, int starty, bool is_rgba)
+{
+ unsigned char *adr;
+ int x, y;
+ int xres;
+ int img_byte_per_pixel = 3;
+
+ if (is_rgba)
+ img_byte_per_pixel++;
+
+ xres = info->xres;
+
+ for (y = 0; y < height; y++) {
+ adr = buf + ((y + starty) * xres + startx) *
+ (info->bits_per_pixel >> 3);
+
+ for (x = 0; x < width; x++) {
+ char *pixel;
+
+ pixel = image;
+ if (is_rgba)
+ set_rgba_pixel(info, adr, pixel[0], pixel[1],
+ pixel[2], pixel[3]);
+ else
+ set_rgb_pixel(info, adr, pixel[0], pixel[1],
+ pixel[2]);
+ adr += info->bits_per_pixel >> 3;
+ image += img_byte_per_pixel;
+ }
+ }
+}
diff --git a/lib/image_renderer.c b/lib/image_renderer.c
new file mode 100644
index 0000000000..b08f6bf2a5
--- /dev/null
+++ b/lib/image_renderer.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2
+ */
+
+#include <common.h>
+#include <fb.h>
+#include <image_renderer.h>
+#include <errno.h>
+#include <fs.h>
+#include <malloc.h>
+
+static LIST_HEAD(image_renderers);
+
+static struct image_renderer *get_renderer(void* buf)
+{
+ struct image_renderer *ir;
+ enum filetype type = file_detect_type(buf);
+
+ list_for_each_entry(ir, &image_renderers, list) {
+ if (ir->type == type)
+ return ir;
+ }
+
+ return NULL;
+}
+
+struct image *image_renderer_open(const char* file)
+{
+ void *data;
+ int size;
+ struct image_renderer *ir;
+ struct image *img;
+ int ret;
+
+ data = read_file(file, &size);
+ if (!data) {
+ printf("unable to read %s\n", file);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ ir = get_renderer(data);
+ if (!ir) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ img = ir->open(data, size);
+ if (IS_ERR(img)) {
+ ret = PTR_ERR(img);
+ goto out;
+ }
+ img->ir = ir;
+ if (!ir->keep_file_data)
+ free(data);
+
+ return img;
+out:
+ free(data);
+ return ERR_PTR(ret);
+}
+
+void image_renderer_close(struct image *img)
+{
+ if (!img)
+ return;
+
+ img->ir->close(img);
+
+ free(img);
+}
+
+int image_renderer_image(struct fb_info *info, struct image *img, void* fb,
+ int startx, int starty, void* offscreenbuf)
+{
+ return img->ir->renderer(info, img, fb, startx, starty, offscreenbuf);
+}
+
+int image_renderer_register(struct image_renderer *ir)
+{
+ if (!ir || !ir->type || !ir->renderer || !ir->open || !ir->close)
+ return -EIO;
+
+ list_add_tail(&ir->list, &image_renderers);
+
+ return 0;
+}
+
+void image_renderer_unregister(struct image_renderer *ir)
+{
+ if (!ir)
+ return;
+
+ list_del(&ir->list);
+}
diff --git a/lib/libbb.c b/lib/libbb.c
index 9a0a60bdb8..e0d7481594 100644
--- a/lib/libbb.c
+++ b/lib/libbb.c
@@ -1,4 +1,3 @@
-/* vi: set sw=8 ts=8: */
/*
* Utility routines.
*
diff --git a/lib/lodepng.c b/lib/lodepng.c
new file mode 100644
index 0000000000..ba21cd235f
--- /dev/null
+++ b/lib/lodepng.c
@@ -0,0 +1,5928 @@
+/*
+LodePNG version 20120729
+
+Copyright (c) 2005-2012 Lode Vandevenne
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+*/
+
+/*
+The manual and changelog are in the header file "lodepng.h"
+Rename this file to lodepng.cpp to use it for C++, or to lodepng.c to use it for C.
+*/
+
+#include "lodepng.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __BAREBOX__
+#include <common.h>
+#include <malloc.h>
+#include <fs.h>
+#include <fcntl.h>
+#endif
+
+#ifdef LODEPNG_COMPILE_CPP
+#include <fstream>
+#endif /*LODEPNG_COMPILE_CPP*/
+
+#define VERSION_STRING "20120729"
+
+/*
+This source file is built up in the following large parts. The code sections
+with the "LODEPNG_COMPILE_" #defines divide this up further in an intermixed way.
+-Tools for C and common code for PNG and Zlib
+-C Code for Zlib (huffman, deflate, ...)
+-C Code for PNG (file format chunks, adam7, PNG filters, color conversions, ...)
+-The C++ wrapper around all of the above
+*/
+
+/*The malloc, realloc and free functions defined here with "my" in front of the
+name, so that you can easily change them to others related to your platform in
+this one location if needed. Everything else in the code calls these.*/
+
+static void* mymalloc(size_t size)
+{
+ return malloc(size);
+}
+
+static void* myrealloc(void* ptr, size_t new_size)
+{
+ return realloc(ptr, new_size);
+}
+
+static void myfree(void* ptr)
+{
+ free(ptr);
+}
+
+/*
+Declaration of the custom functions used if LODEPNG_COMPILE_ZLIB isn't defined
+or LODEPNG_CUSTOM_ZLIB_DECODER or LODEPNG_CUSTOM_ZLIB_ENCODER are enabled.
+
+In that case, you need to define these yourself (which you can do in one of your
+own source files) so that LodePNG can link to it.
+
+By default, this is not needed. If LODEPNG_COMPILE_ZLIB isn't defined, then only
+the two zlib related ones are needed.
+
+If needed, the functions must act as follows:
+*out must be NULL and *outsize must be 0 initially, and after the function is done,
+*out must point to the decompressed data, *outsize must be the size of it, and must
+be the size of the useful data in bytes, not the alloc size.
+*/
+unsigned lodepng_custom_zlib_decompress(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings* settings);
+unsigned lodepng_custom_zlib_compress(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings* settings);
+unsigned lodepng_custom_inflate(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings* settings);
+unsigned lodepng_custom_deflate(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings* settings);
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // Tools for C, and common code for PNG and Zlib. // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*
+Often in case of an error a value is assigned to a variable and then it breaks
+out of a loop (to go to the cleanup phase of a function). This macro does that.
+It makes the error handling code shorter and more readable.
+
+Example: if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83);
+*/
+#define CERROR_BREAK(errorvar, code)\
+{\
+ errorvar = code;\
+ break;\
+}
+
+/*version of CERROR_BREAK that assumes the common case where the error variable is named "error"*/
+#define ERROR_BREAK(code) CERROR_BREAK(error, code)
+
+/*Set error var to the error code, and return it.*/
+#define CERROR_RETURN_ERROR(errorvar, code)\
+{\
+ errorvar = code;\
+ return code;\
+}
+
+/*Try the code, if it returns error, also return the error.*/
+#define CERROR_TRY_RETURN(call)\
+{\
+ unsigned error = call;\
+ if(error) return error;\
+}
+
+/*
+About uivector, ucvector and string:
+-All of them wrap dynamic arrays or text strings in a similar way.
+-LodePNG was originally written in C++. The vectors replace the std::vectors that were used in the C++ version.
+-The string tools are made to avoid problems with compilers that declare things like strncat as deprecated.
+-They're not used in the interface, only internally in this file as static functions.
+-As with many other structs in this file, the init and cleanup functions serve as ctor and dtor.
+*/
+
+#ifdef LODEPNG_COMPILE_ZLIB
+/*dynamic vector of unsigned ints*/
+typedef struct uivector
+{
+ unsigned* data;
+ size_t size; /*size in number of unsigned longs*/
+ size_t allocsize; /*allocated size in bytes*/
+} uivector;
+
+static void uivector_cleanup(void* p)
+{
+ ((uivector*)p)->size = ((uivector*)p)->allocsize = 0;
+ myfree(((uivector*)p)->data);
+ ((uivector*)p)->data = NULL;
+}
+
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned uivector_resize(uivector* p, size_t size)
+{
+ if(size * sizeof(unsigned) > p->allocsize)
+ {
+ size_t newsize = size * sizeof(unsigned) * 2;
+ void* data = myrealloc(p->data, newsize);
+ if(data)
+ {
+ p->allocsize = newsize;
+ p->data = (unsigned*)data;
+ p->size = size;
+ }
+ else return 0;
+ }
+ else p->size = size;
+ return 1;
+}
+
+/*resize and give all new elements the value*/
+static unsigned uivector_resizev(uivector* p, size_t size, unsigned value)
+{
+ size_t oldsize = p->size, i;
+ if(!uivector_resize(p, size)) return 0;
+ for(i = oldsize; i < size; i++) p->data[i] = value;
+ return 1;
+}
+
+static void uivector_init(uivector* p)
+{
+ p->data = NULL;
+ p->size = p->allocsize = 0;
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned uivector_push_back(uivector* p, unsigned c)
+{
+ if(!uivector_resize(p, p->size + 1)) return 0;
+ p->data[p->size - 1] = c;
+ return 1;
+}
+
+/*copy q to p, returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned uivector_copy(uivector* p, const uivector* q)
+{
+ size_t i;
+ if(!uivector_resize(p, q->size)) return 0;
+ for(i = 0; i < q->size; i++) p->data[i] = q->data[i];
+ return 1;
+}
+
+static void uivector_swap(uivector* p, uivector* q)
+{
+ size_t tmp;
+ unsigned* tmpp;
+ tmp = p->size; p->size = q->size; q->size = tmp;
+ tmp = p->allocsize; p->allocsize = q->allocsize; q->allocsize = tmp;
+ tmpp = p->data; p->data = q->data; q->data = tmpp;
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+/* /////////////////////////////////////////////////////////////////////////// */
+
+/*dynamic vector of unsigned chars*/
+typedef struct ucvector
+{
+ unsigned char* data;
+ size_t size; /*used size*/
+ size_t allocsize; /*allocated size*/
+} ucvector;
+
+static void ucvector_cleanup(void* p)
+{
+ ((ucvector*)p)->size = ((ucvector*)p)->allocsize = 0;
+ myfree(((ucvector*)p)->data);
+ ((ucvector*)p)->data = NULL;
+}
+
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned ucvector_resize(ucvector* p, size_t size)
+{
+ if(size * sizeof(unsigned char) > p->allocsize)
+ {
+ size_t newsize = size * sizeof(unsigned char) * 2;
+ void* data = myrealloc(p->data, newsize);
+ if(data)
+ {
+ p->allocsize = newsize;
+ p->data = (unsigned char*)data;
+ p->size = size;
+ }
+ else return 0; /*error: not enough memory*/
+ }
+ else p->size = size;
+ return 1;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+#ifdef LODEPNG_COMPILE_PNG
+/*resize and give all new elements the value*/
+static unsigned ucvector_resizev(ucvector* p, size_t size, unsigned char value)
+{
+ size_t oldsize = p->size, i;
+ if(!ucvector_resize(p, size)) return 0;
+ for(i = oldsize; i < size; i++) p->data[i] = value;
+ return 1;
+}
+#endif /*LODEPNG_COMPILE_PNG*/
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+static void ucvector_init(ucvector* p)
+{
+ p->data = NULL;
+ p->size = p->allocsize = 0;
+}
+
+#ifdef LODEPNG_COMPILE_ZLIB
+/*you can both convert from vector to buffer&size and vica versa. If you use
+init_buffer to take over a buffer and size, it is not needed to use cleanup*/
+static void ucvector_init_buffer(ucvector* p, unsigned char* buffer, size_t size)
+{
+ p->data = buffer;
+ p->allocsize = p->size = size;
+}
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned ucvector_push_back(ucvector* p, unsigned char c)
+{
+ if(!ucvector_resize(p, p->size + 1)) return 0;
+ p->data[p->size - 1] = c;
+ return 1;
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_PNG
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+/*returns 1 if success, 0 if failure ==> nothing done*/
+static unsigned string_resize(char** out, size_t size)
+{
+ char* data = (char*)myrealloc(*out, size + 1);
+ if(data)
+ {
+ data[size] = 0; /*null termination char*/
+ *out = data;
+ }
+ return data != 0;
+}
+
+/*init a {char*, size_t} pair for use as string*/
+static void string_init(char** out)
+{
+ *out = NULL;
+ string_resize(out, 0);
+}
+
+/*free the above pair again*/
+static void string_cleanup(char** out)
+{
+ myfree(*out);
+ *out = NULL;
+}
+
+static void string_set(char** out, const char* in)
+{
+ size_t insize = strlen(in), i = 0;
+ if(string_resize(out, insize))
+ {
+ for(i = 0; i < insize; i++)
+ {
+ (*out)[i] = in[i];
+ }
+ }
+}
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+unsigned lodepng_read32bitInt(const unsigned char* buffer)
+{
+ return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+}
+
+/*buffer must have at least 4 allocated bytes available*/
+static void lodepng_set32bitInt(unsigned char* buffer, unsigned value)
+{
+ buffer[0] = (unsigned char)((value >> 24) & 0xff);
+ buffer[1] = (unsigned char)((value >> 16) & 0xff);
+ buffer[2] = (unsigned char)((value >> 8) & 0xff);
+ buffer[3] = (unsigned char)((value ) & 0xff);
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+static void lodepng_add32bitInt(ucvector* buffer, unsigned value)
+{
+ ucvector_resize(buffer, buffer->size + 4); /*todo: give error if resize failed*/
+ lodepng_set32bitInt(&buffer->data[buffer->size - 4], value);
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / File IO / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_DISK
+
+unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename)
+{
+ FILE* file;
+ long size;
+
+ /*provide some proper output values if error will happen*/
+ *out = 0;
+ *outsize = 0;
+
+ file = fopen(filename, "rb");
+ if(!file) return 78;
+
+ /*get filesize:*/
+ fseek(file , 0 , SEEK_END);
+ size = ftell(file);
+ rewind(file);
+
+ /*read contents of the file into the vector*/
+ *outsize = 0;
+ *out = (unsigned char*)mymalloc((size_t)size);
+ if(size && (*out)) (*outsize) = fread(*out, 1, (size_t)size, file);
+
+ fclose(file);
+ if(!(*out) && size) return 83; /*the above malloc failed*/
+ return 0;
+}
+
+/*write given buffer to the file, overwriting the file, it doesn't append to it.*/
+unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename)
+{
+ FILE* file;
+ file = fopen(filename, "wb" );
+ if(!file) return 79;
+ fwrite((char*)buffer , 1 , buffersize, file);
+ fclose(file);
+ return 0;
+}
+
+#endif /*LODEPNG_COMPILE_DISK*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // End of common code and tools. Begin of Zlib related code. // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_ZLIB
+#ifdef LODEPNG_COMPILE_ENCODER
+/*TODO: this ignores potential out of memory errors*/
+static void addBitToStream(size_t* bitpointer, ucvector* bitstream, unsigned char bit)
+{
+ /*add a new byte at the end*/
+ if((*bitpointer) % 8 == 0) ucvector_push_back(bitstream, (unsigned char)0);
+ /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/
+ (bitstream->data[bitstream->size - 1]) |= (bit << ((*bitpointer) & 0x7));
+ (*bitpointer)++;
+}
+
+static void addBitsToStream(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
+{
+ size_t i;
+ for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> i) & 1));
+}
+
+static void addBitsToStreamReversed(size_t* bitpointer, ucvector* bitstream, unsigned value, size_t nbits)
+{
+ size_t i;
+ for(i = 0; i < nbits; i++) addBitToStream(bitpointer, bitstream, (unsigned char)((value >> (nbits - 1 - i)) & 1));
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+#define READBIT(bitpointer, bitstream) ((bitstream[bitpointer >> 3] >> (bitpointer & 0x7)) & (unsigned char)1)
+
+static unsigned char readBitFromStream(size_t* bitpointer, const unsigned char* bitstream)
+{
+ unsigned char result = (unsigned char)(READBIT(*bitpointer, bitstream));
+ (*bitpointer)++;
+ return result;
+}
+
+static unsigned readBitsFromStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
+{
+ unsigned result = 0, i;
+ for(i = 0; i < nbits; i++)
+ {
+ result += ((unsigned)READBIT(*bitpointer, bitstream)) << i;
+ (*bitpointer)++;
+ }
+ return result;
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Deflate - Huffman / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#define FIRST_LENGTH_CODE_INDEX 257
+#define LAST_LENGTH_CODE_INDEX 285
+/*256 literals, the end code, some length codes, and 2 unused codes*/
+#define NUM_DEFLATE_CODE_SYMBOLS 288
+/*the distance codes have their own symbols, 30 used, 2 unused*/
+#define NUM_DISTANCE_SYMBOLS 32
+/*the code length codes. 0-15: code lengths, 16: copy previous 3-6 times, 17: 3-10 zeros, 18: 11-138 zeros*/
+#define NUM_CODE_LENGTH_CODES 19
+
+/*the base lengths represented by codes 257-285*/
+static const unsigned LENGTHBASE[29]
+ = {3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59,
+ 67, 83, 99, 115, 131, 163, 195, 227, 258};
+
+/*the extra bits used by codes 257-285 (added to base length)*/
+static const unsigned LENGTHEXTRA[29]
+ = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 5, 0};
+
+/*the base backwards distances (the bits of distance codes appear after length codes and use their own huffman tree)*/
+static const unsigned DISTANCEBASE[30]
+ = {1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513,
+ 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577};
+
+/*the extra bits of backwards distances (added to base)*/
+static const unsigned DISTANCEEXTRA[30]
+ = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
+ 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
+
+/*the order in which "code length alphabet code lengths" are stored, out of this
+the huffman tree of the dynamic huffman tree lengths is generated*/
+static const unsigned CLCL_ORDER[NUM_CODE_LENGTH_CODES]
+ = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*
+Huffman tree struct, containing multiple representations of the tree
+*/
+typedef struct HuffmanTree
+{
+ unsigned* tree2d;
+ unsigned* tree1d;
+ unsigned* lengths; /*the lengths of the codes of the 1d-tree*/
+ unsigned maxbitlen; /*maximum number of bits a single code can get*/
+ unsigned numcodes; /*number of symbols in the alphabet = number of codes*/
+} HuffmanTree;
+
+/*function used for debug purposes to draw the tree in ascii art with C++*/
+/*#include <iostream>
+static void HuffmanTree_draw(HuffmanTree* tree)
+{
+ std::cout << "tree. length: " << tree->numcodes << " maxbitlen: " << tree->maxbitlen << std::endl;
+ for(size_t i = 0; i < tree->tree1d.size; i++)
+ {
+ if(tree->lengths.data[i])
+ std::cout << i << " " << tree->tree1d.data[i] << " " << tree->lengths.data[i] << std::endl;
+ }
+ std::cout << std::endl;
+}*/
+
+static void HuffmanTree_init(HuffmanTree* tree)
+{
+ tree->tree2d = 0;
+ tree->tree1d = 0;
+ tree->lengths = 0;
+}
+
+static void HuffmanTree_cleanup(HuffmanTree* tree)
+{
+ myfree(tree->tree2d);
+ myfree(tree->tree1d);
+ myfree(tree->lengths);
+}
+
+/*the tree representation used by the decoder. return value is error*/
+static unsigned HuffmanTree_make2DTree(HuffmanTree* tree)
+{
+ unsigned nodefilled = 0; /*up to which node it is filled*/
+ unsigned treepos = 0; /*position in the tree (1 of the numcodes columns)*/
+ unsigned n, i;
+
+ tree->tree2d = (unsigned*)mymalloc(tree->numcodes * 2 * sizeof(unsigned));
+ if(!tree->tree2d) return 83; /*alloc fail*/
+
+ /*
+ convert tree1d[] to tree2d[][]. In the 2D array, a value of 32767 means
+ uninited, a value >= numcodes is an address to another bit, a value < numcodes
+ is a code. The 2 rows are the 2 possible bit values (0 or 1), there are as
+ many columns as codes - 1.
+ A good huffmann tree has N * 2 - 1 nodes, of which N - 1 are internal nodes.
+ Here, the internal nodes are stored (what their 0 and 1 option point to).
+ There is only memory for such good tree currently, if there are more nodes
+ (due to too long length codes), error 55 will happen
+ */
+ for(n = 0; n < tree->numcodes * 2; n++)
+ {
+ tree->tree2d[n] = 32767; /*32767 here means the tree2d isn't filled there yet*/
+ }
+
+ for(n = 0; n < tree->numcodes; n++) /*the codes*/
+ {
+ for(i = 0; i < tree->lengths[n]; i++) /*the bits for this code*/
+ {
+ unsigned char bit = (unsigned char)((tree->tree1d[n] >> (tree->lengths[n] - i - 1)) & 1);
+ if(treepos > tree->numcodes - 2) return 55; /*oversubscribed, see comment in lodepng_error_text*/
+ if(tree->tree2d[2 * treepos + bit] == 32767) /*not yet filled in*/
+ {
+ if(i + 1 == tree->lengths[n]) /*last bit*/
+ {
+ tree->tree2d[2 * treepos + bit] = n; /*put the current code in it*/
+ treepos = 0;
+ }
+ else
+ {
+ /*put address of the next step in here, first that address has to be found of course
+ (it's just nodefilled + 1)...*/
+ nodefilled++;
+ /*addresses encoded with numcodes added to it*/
+ tree->tree2d[2 * treepos + bit] = nodefilled + tree->numcodes;
+ treepos = nodefilled;
+ }
+ }
+ else treepos = tree->tree2d[2 * treepos + bit] - tree->numcodes;
+ }
+ }
+
+ for(n = 0; n < tree->numcodes * 2; n++)
+ {
+ if(tree->tree2d[n] == 32767) tree->tree2d[n] = 0; /*remove possible remaining 32767's*/
+ }
+
+ return 0;
+}
+
+/*
+Second step for the ...makeFromLengths and ...makeFromFrequencies functions.
+numcodes, lengths and maxbitlen must already be filled in correctly. return
+value is error.
+*/
+static unsigned HuffmanTree_makeFromLengths2(HuffmanTree* tree)
+{
+ uivector blcount;
+ uivector nextcode;
+ unsigned bits, n, error = 0;
+
+ uivector_init(&blcount);
+ uivector_init(&nextcode);
+
+ tree->tree1d = (unsigned*)mymalloc(tree->numcodes * sizeof(unsigned));
+ if(!tree->tree1d) error = 83; /*alloc fail*/
+
+ if(!uivector_resizev(&blcount, tree->maxbitlen + 1, 0)
+ || !uivector_resizev(&nextcode, tree->maxbitlen + 1, 0))
+ error = 83; /*alloc fail*/
+
+ if(!error)
+ {
+ /*step 1: count number of instances of each code length*/
+ for(bits = 0; bits < tree->numcodes; bits++) blcount.data[tree->lengths[bits]]++;
+ /*step 2: generate the nextcode values*/
+ for(bits = 1; bits <= tree->maxbitlen; bits++)
+ {
+ nextcode.data[bits] = (nextcode.data[bits - 1] + blcount.data[bits - 1]) << 1;
+ }
+ /*step 3: generate all the codes*/
+ for(n = 0; n < tree->numcodes; n++)
+ {
+ if(tree->lengths[n] != 0) tree->tree1d[n] = nextcode.data[tree->lengths[n]]++;
+ }
+ }
+
+ uivector_cleanup(&blcount);
+ uivector_cleanup(&nextcode);
+
+ if(!error) return HuffmanTree_make2DTree(tree);
+ else return error;
+}
+
+/*
+given the code lengths (as stored in the PNG file), generate the tree as defined
+by Deflate. maxbitlen is the maximum bits that a code in the tree can have.
+return value is error.
+*/
+static unsigned HuffmanTree_makeFromLengths(HuffmanTree* tree, const unsigned* bitlen,
+ size_t numcodes, unsigned maxbitlen)
+{
+ unsigned i;
+ tree->lengths = (unsigned*)mymalloc(numcodes * sizeof(unsigned));
+ if(!tree->lengths) return 83; /*alloc fail*/
+ for(i = 0; i < numcodes; i++) tree->lengths[i] = bitlen[i];
+ tree->numcodes = (unsigned)numcodes; /*number of symbols*/
+ tree->maxbitlen = maxbitlen;
+ return HuffmanTree_makeFromLengths2(tree);
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/*
+A coin, this is the terminology used for the package-merge algorithm and the
+coin collector's problem. This is used to generate the huffman tree.
+A coin can be multiple coins (when they're merged)
+*/
+typedef struct Coin
+{
+ uivector symbols;
+ float weight; /*the sum of all weights in this coin*/
+} Coin;
+
+static void coin_init(Coin* c)
+{
+ uivector_init(&c->symbols);
+}
+
+/*argument c is void* so that this dtor can be given as function pointer to the vector resize function*/
+static void coin_cleanup(void* c)
+{
+ uivector_cleanup(&((Coin*)c)->symbols);
+}
+
+static void coin_copy(Coin* c1, const Coin* c2)
+{
+ c1->weight = c2->weight;
+ uivector_copy(&c1->symbols, &c2->symbols);
+}
+
+static void add_coins(Coin* c1, const Coin* c2)
+{
+ size_t i;
+ for(i = 0; i < c2->symbols.size; i++) uivector_push_back(&c1->symbols, c2->symbols.data[i]);
+ c1->weight += c2->weight;
+}
+
+static void init_coins(Coin* coins, size_t num)
+{
+ size_t i;
+ for(i = 0; i < num; i++) coin_init(&coins[i]);
+}
+
+static void cleanup_coins(Coin* coins, size_t num)
+{
+ size_t i;
+ for(i = 0; i < num; i++) coin_cleanup(&coins[i]);
+}
+
+/*
+This uses a simple combsort to sort the data. This function is not critical for
+overall encoding speed and the data amount isn't that large.
+*/
+static void sort_coins(Coin* data, size_t amount)
+{
+ size_t gap = amount;
+ unsigned char swapped = 0;
+ while((gap > 1) || swapped)
+ {
+ size_t i;
+ gap = (gap * 10) / 13; /*shrink factor 1.3*/
+ if(gap == 9 || gap == 10) gap = 11; /*combsort11*/
+ if(gap < 1) gap = 1;
+ swapped = 0;
+ for(i = 0; i < amount - gap; i++)
+ {
+ size_t j = i + gap;
+ if(data[j].weight < data[i].weight)
+ {
+ float temp = data[j].weight; data[j].weight = data[i].weight; data[i].weight = temp;
+ uivector_swap(&data[i].symbols, &data[j].symbols);
+ swapped = 1;
+ }
+ }
+ }
+}
+
+static unsigned append_symbol_coins(Coin* coins, const unsigned* frequencies, unsigned numcodes, size_t sum)
+{
+ unsigned i;
+ unsigned j = 0; /*index of present symbols*/
+ for(i = 0; i < numcodes; i++)
+ {
+ if(frequencies[i] != 0) /*only include symbols that are present*/
+ {
+ coins[j].weight = frequencies[i] / (float)sum;
+ uivector_push_back(&coins[j].symbols, i);
+ j++;
+ }
+ }
+ return 0;
+}
+
+unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,
+ size_t numcodes, unsigned maxbitlen)
+{
+ unsigned i, j;
+ size_t sum = 0, numpresent = 0;
+ unsigned error = 0;
+ Coin* coins; /*the coins of the currently calculated row*/
+ Coin* prev_row; /*the previous row of coins*/
+ unsigned numcoins;
+ unsigned coinmem;
+
+ if(numcodes == 0) return 80; /*error: a tree of 0 symbols is not supposed to be made*/
+
+ for(i = 0; i < numcodes; i++)
+ {
+ if(frequencies[i] > 0)
+ {
+ numpresent++;
+ sum += frequencies[i];
+ }
+ }
+
+ for(i = 0; i < numcodes; i++) lengths[i] = 0;
+
+ /*there are no symbols at all, in that case add one symbol of value 0 to the tree (see RFC 1951 section 3.2.7) */
+ if(numpresent == 0)
+ {
+ lengths[0] = 1;
+ }
+ /*the package merge algorithm gives wrong results if there's only one symbol
+ (theoretically 0 bits would then suffice, but we need a proper symbol for zlib)*/
+ else if(numpresent == 1)
+ {
+ for(i = 0; i < numcodes; i++) if(frequencies[i]) lengths[i] = 1;
+ }
+ else
+ {
+ /*Package-Merge algorithm represented by coin collector's problem
+ For every symbol, maxbitlen coins will be created*/
+
+ coinmem = numpresent * 2; /*max amount of coins needed with the current algo*/
+ coins = (Coin*)mymalloc(sizeof(Coin) * coinmem);
+ prev_row = (Coin*)mymalloc(sizeof(Coin) * coinmem);
+ if(!coins || !prev_row) return 83; /*alloc fail*/
+ init_coins(coins, coinmem);
+ init_coins(prev_row, coinmem);
+
+ /*first row, lowest denominator*/
+ error = append_symbol_coins(coins, frequencies, numcodes, sum);
+ numcoins = numpresent;
+ sort_coins(coins, numcoins);
+ if(!error)
+ {
+ unsigned numprev = 0;
+ for(j = 1; j <= maxbitlen && !error; j++) /*each of the remaining rows*/
+ {
+ unsigned tempnum;
+ Coin* tempcoins;
+ /*swap prev_row and coins, and their amounts*/
+ tempcoins = prev_row; prev_row = coins; coins = tempcoins;
+ tempnum = numprev; numprev = numcoins; numcoins = tempnum;
+
+ cleanup_coins(coins, numcoins);
+ init_coins(coins, numcoins);
+
+ numcoins = 0;
+
+ /*fill in the merged coins of the previous row*/
+ for(i = 0; i + 1 < numprev; i += 2)
+ {
+ /*merge prev_row[i] and prev_row[i + 1] into new coin*/
+ Coin* coin = &coins[numcoins++];
+ coin_copy(coin, &prev_row[i]);
+ add_coins(coin, &prev_row[i + 1]);
+ }
+ /*fill in all the original symbols again*/
+ if(j < maxbitlen)
+ {
+ error = append_symbol_coins(coins + numcoins, frequencies, numcodes, sum);
+ numcoins += numpresent;
+ }
+ sort_coins(coins, numcoins);
+ }
+ }
+
+ if(!error)
+ {
+ /*calculate the lenghts of each symbol, as the amount of times a coin of each symbol is used*/
+ for(i = 0; i < numpresent - 1; i++)
+ {
+ Coin* coin = &coins[i];
+ for(j = 0; j < coin->symbols.size; j++) lengths[coin->symbols.data[j]]++;
+ }
+ }
+
+ cleanup_coins(coins, coinmem);
+ myfree(coins);
+ cleanup_coins(prev_row, coinmem);
+ myfree(prev_row);
+ }
+
+ return error;
+}
+
+/*Create the Huffman tree given the symbol frequencies*/
+static unsigned HuffmanTree_makeFromFrequencies(HuffmanTree* tree, const unsigned* frequencies,
+ size_t numcodes, unsigned maxbitlen)
+{
+ unsigned error = 0;
+ tree->maxbitlen = maxbitlen;
+ tree->numcodes = (unsigned)numcodes; /*number of symbols*/
+ tree->lengths = (unsigned*)myrealloc(tree->lengths, numcodes * sizeof(unsigned));
+ if(!tree->lengths) return 83; /*alloc fail*/
+ /*initialize all lengths to 0*/
+ memset(tree->lengths, 0, numcodes * sizeof(unsigned));
+
+ error = lodepng_huffman_code_lengths(tree->lengths, frequencies, numcodes, maxbitlen);
+ if(!error) error = HuffmanTree_makeFromLengths2(tree);
+ return error;
+}
+
+static unsigned HuffmanTree_getCode(const HuffmanTree* tree, unsigned index)
+{
+ return tree->tree1d[index];
+}
+
+static unsigned HuffmanTree_getLength(const HuffmanTree* tree, unsigned index)
+{
+ return tree->lengths[index];
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/*get the literal and length code tree of a deflated block with fixed tree, as per the deflate specification*/
+static unsigned generateFixedLitLenTree(HuffmanTree* tree)
+{
+ unsigned i, error = 0;
+ unsigned* bitlen = (unsigned*)mymalloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
+ if(!bitlen) return 83; /*alloc fail*/
+
+ /*288 possible codes: 0-255=literals, 256=endcode, 257-285=lengthcodes, 286-287=unused*/
+ for(i = 0; i <= 143; i++) bitlen[i] = 8;
+ for(i = 144; i <= 255; i++) bitlen[i] = 9;
+ for(i = 256; i <= 279; i++) bitlen[i] = 7;
+ for(i = 280; i <= 287; i++) bitlen[i] = 8;
+
+ error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DEFLATE_CODE_SYMBOLS, 15);
+
+ myfree(bitlen);
+ return error;
+}
+
+/*get the distance code tree of a deflated block with fixed tree, as specified in the deflate specification*/
+static unsigned generateFixedDistanceTree(HuffmanTree* tree)
+{
+ unsigned i, error = 0;
+ unsigned* bitlen = (unsigned*)mymalloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
+ if(!bitlen) return 83; /*alloc fail*/
+
+ /*there are 32 distance codes, but 30-31 are unused*/
+ for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen[i] = 5;
+ error = HuffmanTree_makeFromLengths(tree, bitlen, NUM_DISTANCE_SYMBOLS, 15);
+
+ myfree(bitlen);
+ return error;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+/*
+returns the code, or (unsigned)(-1) if error happened
+inbitlength is the length of the complete buffer, in bits (so its byte length times 8)
+*/
+static unsigned huffmanDecodeSymbol(const unsigned char* in, size_t* bp,
+ const HuffmanTree* codetree, size_t inbitlength)
+{
+ unsigned treepos = 0, ct;
+ for(;;)
+ {
+ if(*bp >= inbitlength) return (unsigned)(-1); /*error: end of input memory reached without endcode*/
+ /*
+ decode the symbol from the tree. The "readBitFromStream" code is inlined in
+ the expression below because this is the biggest bottleneck while decoding
+ */
+ ct = codetree->tree2d[(treepos << 1) + READBIT(*bp, in)];
+ (*bp)++;
+ if(ct < codetree->numcodes) return ct; /*the symbol is decoded, return it*/
+ else treepos = ct - codetree->numcodes; /*symbol not yet decoded, instead move tree position*/
+
+ if(treepos >= codetree->numcodes) return (unsigned)(-1); /*error: it appeared outside the codetree*/
+ }
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Inflator (Decompressor) / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*get the tree of a deflated block with fixed tree, as specified in the deflate specification*/
+static void getTreeInflateFixed(HuffmanTree* tree_ll, HuffmanTree* tree_d)
+{
+ /*TODO: check for out of memory errors*/
+ generateFixedLitLenTree(tree_ll);
+ generateFixedDistanceTree(tree_d);
+}
+
+/*get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree*/
+static unsigned getTreeInflateDynamic(HuffmanTree* tree_ll, HuffmanTree* tree_d,
+ const unsigned char* in, size_t* bp, size_t inlength)
+{
+ /*make sure that length values that aren't filled in will be 0, or a wrong tree will be generated*/
+ unsigned error = 0;
+ unsigned n, HLIT, HDIST, HCLEN, i;
+ size_t inbitlength = inlength * 8;
+
+ /*see comments in deflateDynamic for explanation of the context and these variables, it is analogous*/
+ unsigned* bitlen_ll = 0; /*lit,len code lengths*/
+ unsigned* bitlen_d = 0; /*dist code lengths*/
+ /*code length code lengths ("clcl"), the bit lengths of the huffman tree used to compress bitlen_ll and bitlen_d*/
+ unsigned* bitlen_cl = 0;
+ HuffmanTree tree_cl; /*the code tree for code length codes (the huffman tree for compressed huffman trees)*/
+
+ if((*bp) >> 3 >= inlength - 2) return 49; /*error: the bit pointer is or will go past the memory*/
+
+ /*number of literal/length codes + 257. Unlike the spec, the value 257 is added to it here already*/
+ HLIT = readBitsFromStream(bp, in, 5) + 257;
+ /*number of distance codes. Unlike the spec, the value 1 is added to it here already*/
+ HDIST = readBitsFromStream(bp, in, 5) + 1;
+ /*number of code length codes. Unlike the spec, the value 4 is added to it here already*/
+ HCLEN = readBitsFromStream(bp, in, 4) + 4;
+
+ HuffmanTree_init(&tree_cl);
+
+ while(!error)
+ {
+ /*read the code length codes out of 3 * (amount of code length codes) bits*/
+
+ bitlen_cl = (unsigned*)mymalloc(NUM_CODE_LENGTH_CODES * sizeof(unsigned));
+ if(!bitlen_cl) ERROR_BREAK(83 /*alloc fail*/);
+
+ for(i = 0; i < NUM_CODE_LENGTH_CODES; i++)
+ {
+ if(i < HCLEN) bitlen_cl[CLCL_ORDER[i]] = readBitsFromStream(bp, in, 3);
+ else bitlen_cl[CLCL_ORDER[i]] = 0; /*if not, it must stay 0*/
+ }
+
+ error = HuffmanTree_makeFromLengths(&tree_cl, bitlen_cl, NUM_CODE_LENGTH_CODES, 7);
+ if(error) break;
+
+ /*now we can use this tree to read the lengths for the tree that this function will return*/
+ bitlen_ll = (unsigned*)mymalloc(NUM_DEFLATE_CODE_SYMBOLS * sizeof(unsigned));
+ bitlen_d = (unsigned*)mymalloc(NUM_DISTANCE_SYMBOLS * sizeof(unsigned));
+ if(!bitlen_ll || !bitlen_d) ERROR_BREAK(83 /*alloc fail*/);
+ for(i = 0; i < NUM_DEFLATE_CODE_SYMBOLS; i++) bitlen_ll[i] = 0;
+ for(i = 0; i < NUM_DISTANCE_SYMBOLS; i++) bitlen_d[i] = 0;
+
+ /*i is the current symbol we're reading in the part that contains the code lengths of lit/len and dist codes*/
+ i = 0;
+ while(i < HLIT + HDIST)
+ {
+ unsigned code = huffmanDecodeSymbol(in, bp, &tree_cl, inbitlength);
+ if(code <= 15) /*a length code*/
+ {
+ if(i < HLIT) bitlen_ll[i] = code;
+ else bitlen_d[i - HLIT] = code;
+ i++;
+ }
+ else if(code == 16) /*repeat previous*/
+ {
+ unsigned replength = 3; /*read in the 2 bits that indicate repeat length (3-6)*/
+ unsigned value; /*set value to the previous code*/
+
+ if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
+ if (i == 0) ERROR_BREAK(54); /*can't repeat previous if i is 0*/
+
+ replength += readBitsFromStream(bp, in, 2);
+
+ if(i < HLIT + 1) value = bitlen_ll[i - 1];
+ else value = bitlen_d[i - HLIT - 1];
+ /*repeat this value in the next lengths*/
+ for(n = 0; n < replength; n++)
+ {
+ if(i >= HLIT + HDIST) ERROR_BREAK(13); /*error: i is larger than the amount of codes*/
+ if(i < HLIT) bitlen_ll[i] = value;
+ else bitlen_d[i - HLIT] = value;
+ i++;
+ }
+ }
+ else if(code == 17) /*repeat "0" 3-10 times*/
+ {
+ unsigned replength = 3; /*read in the bits that indicate repeat length*/
+ if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
+
+ replength += readBitsFromStream(bp, in, 3);
+
+ /*repeat this value in the next lengths*/
+ for(n = 0; n < replength; n++)
+ {
+ if(i >= HLIT + HDIST) ERROR_BREAK(14); /*error: i is larger than the amount of codes*/
+
+ if(i < HLIT) bitlen_ll[i] = 0;
+ else bitlen_d[i - HLIT] = 0;
+ i++;
+ }
+ }
+ else if(code == 18) /*repeat "0" 11-138 times*/
+ {
+ unsigned replength = 11; /*read in the bits that indicate repeat length*/
+ if(*bp >= inbitlength) ERROR_BREAK(50); /*error, bit pointer jumps past memory*/
+
+ replength += readBitsFromStream(bp, in, 7);
+
+ /*repeat this value in the next lengths*/
+ for(n = 0; n < replength; n++)
+ {
+ if(i >= HLIT + HDIST) ERROR_BREAK(15); /*error: i is larger than the amount of codes*/
+
+ if(i < HLIT) bitlen_ll[i] = 0;
+ else bitlen_d[i - HLIT] = 0;
+ i++;
+ }
+ }
+ else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
+ {
+ if(code == (unsigned)(-1))
+ {
+ /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
+ (10=no endcode, 11=wrong jump outside of tree)*/
+ error = (*bp) > inbitlength ? 10 : 11;
+ }
+ else error = 16; /*unexisting code, this can never happen*/
+ break;
+ }
+ }
+ if(error) break;
+
+ if(bitlen_ll[256] == 0) ERROR_BREAK(64); /*the length of the end code 256 must be larger than 0*/
+
+ /*now we've finally got HLIT and HDIST, so generate the code trees, and the function is done*/
+ error = HuffmanTree_makeFromLengths(tree_ll, bitlen_ll, NUM_DEFLATE_CODE_SYMBOLS, 15);
+ if(error) break;
+ error = HuffmanTree_makeFromLengths(tree_d, bitlen_d, NUM_DISTANCE_SYMBOLS, 15);
+
+ break; /*end of error-while*/
+ }
+
+ myfree(bitlen_cl);
+ myfree(bitlen_ll);
+ myfree(bitlen_d);
+ HuffmanTree_cleanup(&tree_cl);
+
+ return error;
+}
+
+/*inflate a block with dynamic of fixed Huffman tree*/
+static unsigned inflateHuffmanBlock(ucvector* out, const unsigned char* in, size_t* bp,
+ size_t* pos, size_t inlength, unsigned btype)
+{
+ unsigned error = 0;
+ HuffmanTree tree_ll; /*the huffman tree for literal and length codes*/
+ HuffmanTree tree_d; /*the huffman tree for distance codes*/
+ size_t inbitlength = inlength * 8;
+
+ HuffmanTree_init(&tree_ll);
+ HuffmanTree_init(&tree_d);
+
+ if(btype == 1) getTreeInflateFixed(&tree_ll, &tree_d);
+ else if(btype == 2)
+ {
+ error = getTreeInflateDynamic(&tree_ll, &tree_d, in, bp, inlength);
+ }
+
+ while(!error) /*decode all symbols until end reached, breaks at end code*/
+ {
+ /*code_ll is literal, length or end code*/
+ unsigned code_ll = huffmanDecodeSymbol(in, bp, &tree_ll, inbitlength);
+ if(code_ll <= 255) /*literal symbol*/
+ {
+ if((*pos) >= out->size)
+ {
+ /*reserve more room at once*/
+ if(!ucvector_resize(out, ((*pos) + 1) * 2)) ERROR_BREAK(83 /*alloc fail*/);
+ }
+ out->data[(*pos)] = (unsigned char)(code_ll);
+ (*pos)++;
+ }
+ else if(code_ll >= FIRST_LENGTH_CODE_INDEX && code_ll <= LAST_LENGTH_CODE_INDEX) /*length code*/
+ {
+ unsigned code_d, distance;
+ unsigned numextrabits_l, numextrabits_d; /*extra bits for length and distance*/
+ size_t start, forward, backward, length;
+
+ /*part 1: get length base*/
+ length = LENGTHBASE[code_ll - FIRST_LENGTH_CODE_INDEX];
+
+ /*part 2: get extra bits and add the value of that to length*/
+ numextrabits_l = LENGTHEXTRA[code_ll - FIRST_LENGTH_CODE_INDEX];
+ if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
+ length += readBitsFromStream(bp, in, numextrabits_l);
+
+ /*part 3: get distance code*/
+ code_d = huffmanDecodeSymbol(in, bp, &tree_d, inbitlength);
+ if(code_d > 29)
+ {
+ if(code_ll == (unsigned)(-1)) /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
+ {
+ /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
+ (10=no endcode, 11=wrong jump outside of tree)*/
+ error = (*bp) > inlength * 8 ? 10 : 11;
+ }
+ else error = 18; /*error: invalid distance code (30-31 are never used)*/
+ break;
+ }
+ distance = DISTANCEBASE[code_d];
+
+ /*part 4: get extra bits from distance*/
+ numextrabits_d = DISTANCEEXTRA[code_d];
+ if(*bp >= inbitlength) ERROR_BREAK(51); /*error, bit pointer will jump past memory*/
+
+ distance += readBitsFromStream(bp, in, numextrabits_d);
+
+ /*part 5: fill in all the out[n] values based on the length and dist*/
+ start = (*pos);
+ if(distance > start) ERROR_BREAK(52); /*too long backward distance*/
+ backward = start - distance;
+ if((*pos) + length >= out->size)
+ {
+ /*reserve more room at once*/
+ if(!ucvector_resize(out, ((*pos) + length) * 2)) ERROR_BREAK(83 /*alloc fail*/);
+ }
+
+ for(forward = 0; forward < length; forward++)
+ {
+ out->data[(*pos)] = out->data[backward];
+ (*pos)++;
+ backward++;
+ if(backward >= start) backward = start - distance;
+ }
+ }
+ else if(code_ll == 256)
+ {
+ break; /*end code, break the loop*/
+ }
+ else /*if(code == (unsigned)(-1))*/ /*huffmanDecodeSymbol returns (unsigned)(-1) in case of error*/
+ {
+ /*return error code 10 or 11 depending on the situation that happened in huffmanDecodeSymbol
+ (10=no endcode, 11=wrong jump outside of tree)*/
+ error = (*bp) > inlength * 8 ? 10 : 11;
+ break;
+ }
+ }
+
+ HuffmanTree_cleanup(&tree_ll);
+ HuffmanTree_cleanup(&tree_d);
+
+ return error;
+}
+
+static unsigned inflateNoCompression(ucvector* out, const unsigned char* in, size_t* bp, size_t* pos, size_t inlength)
+{
+ /*go to first boundary of byte*/
+ size_t p;
+ unsigned LEN, NLEN, n, error = 0;
+ while(((*bp) & 0x7) != 0) (*bp)++;
+ p = (*bp) / 8; /*byte position*/
+
+ /*read LEN (2 bytes) and NLEN (2 bytes)*/
+ if(p >= inlength - 4) return 52; /*error, bit pointer will jump past memory*/
+ LEN = in[p] + 256 * in[p + 1]; p += 2;
+ NLEN = in[p] + 256 * in[p + 1]; p += 2;
+
+ /*check if 16-bit NLEN is really the one's complement of LEN*/
+ if(LEN + NLEN != 65535) return 21; /*error: NLEN is not one's complement of LEN*/
+
+ if((*pos) + LEN >= out->size)
+ {
+ if(!ucvector_resize(out, (*pos) + LEN)) return 83; /*alloc fail*/
+ }
+
+ /*read the literal data: LEN bytes are now stored in the out buffer*/
+ if(p + LEN > inlength) return 23; /*error: reading outside of in buffer*/
+ for(n = 0; n < LEN; n++) out->data[(*pos)++] = in[p++];
+
+ (*bp) = p * 8;
+
+ return error;
+}
+
+static unsigned lodepng_inflatev(ucvector* out,
+ const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings* settings)
+{
+ /*bit pointer in the "in" data, current byte is bp >> 3, current bit is bp & 0x7 (from lsb to msb of the byte)*/
+ size_t bp = 0;
+ unsigned BFINAL = 0;
+ size_t pos = 0; /*byte position in the out buffer*/
+
+ unsigned error = 0;
+
+ (void)settings;
+
+ while(!BFINAL)
+ {
+ unsigned BTYPE;
+ if(bp + 2 >= insize * 8) return 52; /*error, bit pointer will jump past memory*/
+ BFINAL = readBitFromStream(&bp, in);
+ BTYPE = 1 * readBitFromStream(&bp, in);
+ BTYPE += 2 * readBitFromStream(&bp, in);
+
+ if(BTYPE == 3) return 20; /*error: invalid BTYPE*/
+ else if(BTYPE == 0) error = inflateNoCompression(out, in, &bp, &pos, insize); /*no compression*/
+ else error = inflateHuffmanBlock(out, in, &bp, &pos, insize, BTYPE); /*compression, BTYPE 01 or 10*/
+
+ if(error) return error;
+ }
+
+ /*Only now we know the true size of out, resize it to that*/
+ if(!ucvector_resize(out, pos)) error = 83; /*alloc fail*/
+
+ return error;
+}
+
+unsigned lodepng_inflate(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings* settings)
+{
+#if LODEPNG_CUSTOM_ZLIB_DECODER == 2
+ if(settings->custom_decoder)
+ {
+ return lodepng_custom_inflate(out, outsize, in, insize, settings);
+ }
+ else
+ {
+#endif /*LODEPNG_CUSTOM_ZLIB_DECODER == 2*/
+ unsigned error;
+ ucvector v;
+ ucvector_init_buffer(&v, *out, *outsize);
+ error = lodepng_inflatev(&v, in, insize, settings);
+ *out = v.data;
+ *outsize = v.size;
+ return error;
+#if LODEPNG_CUSTOM_ZLIB_DECODER == 2
+ }
+#endif /*LODEPNG_CUSTOM_ZLIB_DECODER == 2*/
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Deflator (Compressor) / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+static const size_t MAX_SUPPORTED_DEFLATE_LENGTH = 258;
+
+/*bitlen is the size in bits of the code*/
+static void addHuffmanSymbol(size_t* bp, ucvector* compressed, unsigned code, unsigned bitlen)
+{
+ addBitsToStreamReversed(bp, compressed, code, bitlen);
+}
+
+/*search the index in the array, that has the largest value smaller than or equal to the given value,
+given array must be sorted (if no value is smaller, it returns the size of the given array)*/
+static size_t searchCodeIndex(const unsigned* array, size_t array_size, size_t value)
+{
+ /*linear search implementation*/
+ /*for(size_t i = 1; i < array_size; i++) if(array[i] > value) return i - 1;
+ return array_size - 1;*/
+
+ /*binary search implementation (not that much faster) (precondition: array_size > 0)*/
+ size_t left = 1;
+ size_t right = array_size - 1;
+ while(left <= right)
+ {
+ size_t mid = (left + right) / 2;
+ if(array[mid] <= value) left = mid + 1; /*the value to find is more to the right*/
+ else if(array[mid - 1] > value) right = mid - 1; /*the value to find is more to the left*/
+ else return mid - 1;
+ }
+ return array_size - 1;
+}
+
+static void addLengthDistance(uivector* values, size_t length, size_t distance)
+{
+ /*values in encoded vector are those used by deflate:
+ 0-255: literal bytes
+ 256: end
+ 257-285: length/distance pair (length code, followed by extra length bits, distance code, extra distance bits)
+ 286-287: invalid*/
+
+ unsigned length_code = (unsigned)searchCodeIndex(LENGTHBASE, 29, length);
+ unsigned extra_length = (unsigned)(length - LENGTHBASE[length_code]);
+ unsigned dist_code = (unsigned)searchCodeIndex(DISTANCEBASE, 30, distance);
+ unsigned extra_distance = (unsigned)(distance - DISTANCEBASE[dist_code]);
+
+ uivector_push_back(values, length_code + FIRST_LENGTH_CODE_INDEX);
+ uivector_push_back(values, extra_length);
+ uivector_push_back(values, dist_code);
+ uivector_push_back(values, extra_distance);
+}
+
+static const unsigned HASH_NUM_VALUES = 65536;
+static const unsigned HASH_NUM_CHARACTERS = 3;
+static const unsigned HASH_SHIFT = 2;
+/*
+The HASH_NUM_CHARACTERS value is used to make encoding faster by using longer
+sequences to generate a hash value from the stream bytes. Setting it to 3
+gives exactly the same compression as the brute force method, since deflate's
+run length encoding starts with lengths of 3. Setting it to higher values,
+like 6, can make the encoding faster (not always though!), but will cause the
+encoding to miss any length between 3 and this value, so that the compression
+may be worse (but this can vary too depending on the image, sometimes it is
+even a bit better instead).
+The HASH_NUM_VALUES is the amount of unique possible hash values that
+combinations of bytes can give, the higher it is the more memory is needed, but
+if it's too low the advantage of hashing is gone.
+*/
+
+typedef struct Hash
+{
+ int* head; /*hash value to head circular pos*/
+ int* val; /*circular pos to hash value*/
+ /*circular pos to prev circular pos*/
+ unsigned short* chain;
+ unsigned short* zeros;
+} Hash;
+
+static unsigned hash_init(Hash* hash, unsigned windowsize)
+{
+ unsigned i;
+ hash->head = (int*)mymalloc(sizeof(int) * HASH_NUM_VALUES);
+ hash->val = (int*)mymalloc(sizeof(int) * windowsize);
+ hash->chain = (unsigned short*)mymalloc(sizeof(unsigned short) * windowsize);
+ hash->zeros = (unsigned short*)mymalloc(sizeof(unsigned short) * windowsize);
+
+ if(!hash->head || !hash->val || !hash->chain || !hash->zeros) return 83; /*alloc fail*/
+
+ /*initialize hash table*/
+ for(i = 0; i < HASH_NUM_VALUES; i++) hash->head[i] = -1;
+ for(i = 0; i < windowsize; i++) hash->val[i] = -1;
+ for(i = 0; i < windowsize; i++) hash->chain[i] = i; /*same value as index indicates uninitialized*/
+
+ return 0;
+}
+
+static void hash_cleanup(Hash* hash)
+{
+ myfree(hash->head);
+ myfree(hash->val);
+ myfree(hash->chain);
+ myfree(hash->zeros);
+}
+
+static unsigned getHash(const unsigned char* data, size_t size, size_t pos)
+{
+ unsigned result = 0;
+ size_t amount, i;
+ if(pos >= size) return 0;
+ amount = HASH_NUM_CHARACTERS;
+ if(pos + amount >= size) amount = size - pos;
+ for(i = 0; i < amount; i++) result ^= (data[pos + i] << (i * HASH_SHIFT));
+ return result % HASH_NUM_VALUES;
+}
+
+static unsigned countZeros(const unsigned char* data, size_t size, size_t pos)
+{
+ const unsigned char* start = data + pos;
+ const unsigned char* end = start + MAX_SUPPORTED_DEFLATE_LENGTH;
+ if(end > data + size) end = data + size;
+ data = start;
+ while (data != end && *data == 0) data++;
+ return data - start;
+}
+
+static void updateHashChain(Hash* hash,
+ size_t pos, int hashval, unsigned windowsize)
+{
+ unsigned wpos = pos % windowsize;
+ hash->val[wpos] = hashval;
+ if(hash->head[hashval] != -1)
+ {
+ hash->chain[wpos] = hash->head[hashval];
+ }
+ hash->head[hashval] = wpos;
+}
+
+/*Enable to use lazy instead of greedy matching. It looks one byte further
+to see if that one gives a longer distance. This gives slightly better compression, at the cost
+of a speed loss.*/
+#define LAZY_MATCHING
+
+/*
+LZ77-encode the data. Return value is error code. The input are raw bytes, the output
+is in the form of unsigned integers with codes representing for example literal bytes, or
+length/distance pairs.
+It uses a hash table technique to let it encode faster. When doing LZ77 encoding, a
+sliding window (of windowsize) is used, and all past bytes in that window can be used as
+the "dictionary". A brute force search through all possible distances would be slow, and
+this hash technique is one out of several ways to speed this up.
+*/
+static unsigned encodeLZ77(uivector* out, Hash* hash,
+ const unsigned char* in, size_t inpos, size_t insize, unsigned windowsize)
+{
+ unsigned short numzeros = 0;
+ int usezeros = windowsize >= 8192; /*for small window size, the 'max chain length' optimization does a better job*/
+ unsigned pos, i, error = 0;
+
+ if(!error)
+ {
+ unsigned offset; /*the offset represents the distance in LZ77 terminology*/
+ unsigned length;
+#ifdef LAZY_MATCHING
+ unsigned lazy = 0;
+ unsigned lazylength = 0, lazyoffset = 0;
+#endif /*LAZY_MATCHING*/
+ unsigned hashval;
+ unsigned current_offset, current_length;
+ const unsigned char *lastptr, *foreptr, *backptr;
+ unsigned short hashpos, prevpos;
+
+ for(pos = inpos; pos < insize; pos++)
+ {
+ size_t wpos = pos % windowsize; /*position for in 'circular' hash buffers*/
+
+ hashval = getHash(in, insize, pos);
+ updateHashChain(hash, pos, hashval, windowsize);
+
+ if(usezeros && hashval == 0)
+ {
+ numzeros = countZeros(in, insize, pos);
+ hash->zeros[wpos] = numzeros;
+ }
+
+ /*the length and offset found for the current position*/
+ length = 0;
+ offset = 0;
+
+ prevpos = hash->head[hashval];
+ hashpos = hash->chain[prevpos];
+
+ lastptr = &in[insize < pos + MAX_SUPPORTED_DEFLATE_LENGTH ? insize : pos + MAX_SUPPORTED_DEFLATE_LENGTH];
+
+ /*search for the longest string*/
+ if(hash->val[wpos] == (int)hashval)
+ {
+ /*for large window lengths, assume the user wants no compression loss. Otherwise, max hash chain length speedup.*/
+ unsigned maxchainlength = windowsize >= 8192 ? windowsize : windowsize / 8;
+ for(;;)
+ {
+ /*stop when went completely around the circular buffer*/
+ if(prevpos < wpos && hashpos > prevpos && hashpos <= wpos) break;
+ if(prevpos > wpos && (hashpos <= wpos || hashpos > prevpos)) break;
+ if(maxchainlength-- == 0) break;
+
+ current_offset = hashpos <= wpos ? wpos - hashpos : wpos - hashpos + windowsize;
+ if(current_offset > 0)
+ {
+ /*test the next characters*/
+ foreptr = &in[pos];
+ backptr = &in[pos - current_offset];
+
+ /*common case in PNGs is lots of zeros. Quickly skip over them as a speedup*/
+ if(usezeros && hashval == 0 && hash->val[hashpos] == 0 /*hashval[hashpos] may be out of date*/)
+ {
+ unsigned short skip = hash->zeros[hashpos];
+ if(skip > numzeros) skip = numzeros;
+ backptr += skip;
+ foreptr += skip;
+ }
+
+ /* multiple checks at once per array bounds check */
+ while(foreptr != lastptr && *backptr == *foreptr) /*maximum supported length by deflate is max length*/
+ {
+ ++backptr;
+ ++foreptr;
+ }
+ current_length = (unsigned)(foreptr - &in[pos]);
+
+ if(current_length > length)
+ {
+ length = current_length; /*the longest length*/
+ offset = current_offset; /*the offset that is related to this longest length*/
+ /*jump out once a length of max length is found (speed gain)*/
+ if(current_length == MAX_SUPPORTED_DEFLATE_LENGTH) break;
+ }
+ }
+
+ if(hashpos == hash->chain[hashpos]) break;
+
+ prevpos = hashpos;
+ hashpos = hash->chain[hashpos];
+ }
+ }
+
+#ifdef LAZY_MATCHING
+ if(!lazy && length >= 3 && length < MAX_SUPPORTED_DEFLATE_LENGTH)
+ {
+ lazy = 1;
+ lazylength = length;
+ lazyoffset = offset;
+ continue;
+ }
+ if(lazy)
+ {
+ lazy = 0;
+ if(pos == 0) ERROR_BREAK(81);
+ if(length > lazylength + 1)
+ {
+ /*push the previous character as literal*/
+ if(!uivector_push_back(out, in[pos - 1])) ERROR_BREAK(83 /*alloc fail*/);
+ }
+ else
+ {
+ length = lazylength;
+ offset = lazyoffset;
+ hash->head[hashval] = -1; /*the same hashchain update will be done, this ensures no wrong alteration*/
+ pos--;
+ }
+ }
+#endif /*LAZY_MATCHING*/
+
+ if(length >= 3 && offset > windowsize) ERROR_BREAK(86 /*too big (or overflown negative) offset*/);
+
+
+ /**encode it as length/distance pair or literal value**/
+ if(length < 3) /*only lengths of 3 or higher are supported as length/distance pair*/
+ {
+ if(!uivector_push_back(out, in[pos])) ERROR_BREAK(83 /*alloc fail*/);
+ }
+ else
+ {
+ if(length == 3 && offset > 2048)
+ {
+ /*compensate for the fact that longer offsets have more extra bits, a
+ length of only 3 may be not worth it then*/
+ if(!uivector_push_back(out, in[pos + 0])) ERROR_BREAK(83 /*alloc fail*/);
+ if(!uivector_push_back(out, in[pos + 1])) ERROR_BREAK(83 /*alloc fail*/);
+ if(!uivector_push_back(out, in[pos + 2])) ERROR_BREAK(83 /*alloc fail*/);
+ }
+ else
+ {
+ addLengthDistance(out, length, offset);
+ }
+ for(i = 1; i < length; i++)
+ {
+ pos++;
+ hashval = getHash(in, insize, pos);
+ updateHashChain(hash, pos, hashval, windowsize);
+ if(usezeros && hashval == 0)
+ {
+ hash->zeros[pos % windowsize] = countZeros(in, insize, pos);
+ }
+ }
+ }
+
+ } /*end of the loop through each character of input*/
+ } /*end of "if(!error)"*/
+
+ return error;
+}
+
+/* /////////////////////////////////////////////////////////////////////////// */
+
+static unsigned deflateNoCompression(ucvector* out, const unsigned char* data, size_t datasize)
+{
+ /*non compressed deflate block data: 1 bit BFINAL,2 bits BTYPE,(5 bits): it jumps to start of next byte,
+ 2 bytes LEN, 2 bytes NLEN, LEN bytes literal DATA*/
+
+ size_t i, j, numdeflateblocks = (datasize + 65534) / 65535;
+ unsigned datapos = 0;
+ for(i = 0; i < numdeflateblocks; i++)
+ {
+ unsigned BFINAL, BTYPE, LEN, NLEN;
+ unsigned char firstbyte;
+
+ BFINAL = (i == numdeflateblocks - 1);
+ BTYPE = 0;
+
+ firstbyte = (unsigned char)(BFINAL + ((BTYPE & 1) << 1) + ((BTYPE & 2) << 1));
+ ucvector_push_back(out, firstbyte);
+
+ LEN = 65535;
+ if(datasize - datapos < 65535) LEN = (unsigned)datasize - datapos;
+ NLEN = 65535 - LEN;
+
+ ucvector_push_back(out, (unsigned char)(LEN % 256));
+ ucvector_push_back(out, (unsigned char)(LEN / 256));
+ ucvector_push_back(out, (unsigned char)(NLEN % 256));
+ ucvector_push_back(out, (unsigned char)(NLEN / 256));
+
+ /*Decompressed data*/
+ for(j = 0; j < 65535 && datapos < datasize; j++)
+ {
+ ucvector_push_back(out, data[datapos++]);
+ }
+ }
+
+ return 0;
+}
+
+/*
+write the lz77-encoded data, which has lit, len and dist codes, to compressed stream using huffman trees.
+tree_ll: the tree for lit and len codes.
+tree_d: the tree for distance codes.
+*/
+static void writeLZ77data(size_t* bp, ucvector* out, const uivector* lz77_encoded,
+ const HuffmanTree* tree_ll, const HuffmanTree* tree_d)
+{
+ size_t i = 0;
+ for(i = 0; i < lz77_encoded->size; i++)
+ {
+ unsigned val = lz77_encoded->data[i];
+ addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_ll, val), HuffmanTree_getLength(tree_ll, val));
+ if(val > 256) /*for a length code, 3 more things have to be added*/
+ {
+ unsigned length_index = val - FIRST_LENGTH_CODE_INDEX;
+ unsigned n_length_extra_bits = LENGTHEXTRA[length_index];
+ unsigned length_extra_bits = lz77_encoded->data[++i];
+
+ unsigned distance_code = lz77_encoded->data[++i];
+
+ unsigned distance_index = distance_code;
+ unsigned n_distance_extra_bits = DISTANCEEXTRA[distance_index];
+ unsigned distance_extra_bits = lz77_encoded->data[++i];
+
+ addBitsToStream(bp, out, length_extra_bits, n_length_extra_bits);
+ addHuffmanSymbol(bp, out, HuffmanTree_getCode(tree_d, distance_code),
+ HuffmanTree_getLength(tree_d, distance_code));
+ addBitsToStream(bp, out, distance_extra_bits, n_distance_extra_bits);
+ }
+ }
+}
+
+/*Deflate for a block of type "dynamic", that is, with freely, optimally, created huffman trees*/
+static unsigned deflateDynamic(ucvector* out, size_t* bp, Hash* hash,
+ const unsigned char* data, size_t datapos, size_t dataend,
+ const LodePNGCompressSettings* settings, int final)
+{
+ unsigned error = 0;
+
+ /*
+ A block is compressed as follows: The PNG data is lz77 encoded, resulting in
+ literal bytes and length/distance pairs. This is then huffman compressed with
+ two huffman trees. One huffman tree is used for the lit and len values ("ll"),
+ another huffman tree is used for the dist values ("d"). These two trees are
+ stored using their code lengths, and to compress even more these code lengths
+ are also run-length encoded and huffman compressed. This gives a huffman tree
+ of code lengths "cl". The code lenghts used to describe this third tree are
+ the code length code lengths ("clcl").
+ */
+
+ /*The lz77 encoded data, represented with integers since there will also be length and distance codes in it*/
+ uivector lz77_encoded;
+ HuffmanTree tree_ll; /*tree for lit,len values*/
+ HuffmanTree tree_d; /*tree for distance codes*/
+ HuffmanTree tree_cl; /*tree for encoding the code lengths representing tree_ll and tree_d*/
+ uivector frequencies_ll; /*frequency of lit,len codes*/
+ uivector frequencies_d; /*frequency of dist codes*/
+ uivector frequencies_cl; /*frequency of code length codes*/
+ uivector bitlen_lld; /*lit,len,dist code lenghts (int bits), literally (without repeat codes).*/
+ uivector bitlen_lld_e; /*bitlen_lld encoded with repeat codes (this is a rudemtary run length compression)*/
+ /*bitlen_cl is the code length code lengths ("clcl"). The bit lengths of codes to represent tree_cl
+ (these are written as is in the file, it would be crazy to compress these using yet another huffman
+ tree that needs to be represented by yet another set of code lengths)*/
+ uivector bitlen_cl;
+ size_t datasize = dataend - datapos;
+
+ /*
+ Due to the huffman compression of huffman tree representations ("two levels"), there are some anologies:
+ bitlen_lld is to tree_cl what data is to tree_ll and tree_d.
+ bitlen_lld_e is to bitlen_lld what lz77_encoded is to data.
+ bitlen_cl is to bitlen_lld_e what bitlen_lld is to lz77_encoded.
+ */
+
+ unsigned BFINAL = final;
+ size_t numcodes_ll, numcodes_d, i;
+ unsigned HLIT, HDIST, HCLEN;
+
+ uivector_init(&lz77_encoded);
+ HuffmanTree_init(&tree_ll);
+ HuffmanTree_init(&tree_d);
+ HuffmanTree_init(&tree_cl);
+ uivector_init(&frequencies_ll);
+ uivector_init(&frequencies_d);
+ uivector_init(&frequencies_cl);
+ uivector_init(&bitlen_lld);
+ uivector_init(&bitlen_lld_e);
+ uivector_init(&bitlen_cl);
+
+ /*This while loop is never loops due to a break at the end, it is here to
+ allow breaking out of it to the cleanup phase on error conditions.*/
+ while(!error)
+ {
+ if(settings->use_lz77)
+ {
+ error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize); /*LZ77 encoded*/
+ if(error) break;
+ }
+ else
+ {
+ if(!uivector_resize(&lz77_encoded, datasize)) ERROR_BREAK(83 /*alloc fail*/);
+ for(i = datapos; i < dataend; i++) lz77_encoded.data[i] = data[i]; /*no LZ77, but still will be Huffman compressed*/
+ }
+
+ if(!uivector_resizev(&frequencies_ll, 286, 0)) ERROR_BREAK(83 /*alloc fail*/);
+ if(!uivector_resizev(&frequencies_d, 30, 0)) ERROR_BREAK(83 /*alloc fail*/);
+
+ /*Count the frequencies of lit, len and dist codes*/
+ for(i = 0; i < lz77_encoded.size; i++)
+ {
+ unsigned symbol = lz77_encoded.data[i];
+ frequencies_ll.data[symbol]++;
+ if(symbol > 256)
+ {
+ unsigned dist = lz77_encoded.data[i + 2];
+ frequencies_d.data[dist]++;
+ i += 3;
+ }
+ }
+ frequencies_ll.data[256] = 1; /*there will be exactly 1 end code, at the end of the block*/
+
+ /*Make both huffman trees, one for the lit and len codes, one for the dist codes*/
+ error = HuffmanTree_makeFromFrequencies(&tree_ll, frequencies_ll.data, frequencies_ll.size, 15);
+ if(error) break;
+ error = HuffmanTree_makeFromFrequencies(&tree_d, frequencies_d.data, frequencies_d.size, 15);
+ if(error) break;
+
+ numcodes_ll = tree_ll.numcodes; if(numcodes_ll > 286) numcodes_ll = 286;
+ numcodes_d = tree_d.numcodes; if(numcodes_d > 30) numcodes_d = 30;
+ /*store the code lengths of both generated trees in bitlen_lld*/
+ for(i = 0; i < numcodes_ll; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_ll, (unsigned)i));
+ for(i = 0; i < numcodes_d; i++) uivector_push_back(&bitlen_lld, HuffmanTree_getLength(&tree_d, (unsigned)i));
+
+ /*run-length compress bitlen_ldd into bitlen_lld_e by using repeat codes 16 (copy length 3-6 times),
+ 17 (3-10 zeroes), 18 (11-138 zeroes)*/
+ for(i = 0; i < (unsigned)bitlen_lld.size; i++)
+ {
+ unsigned j = 0; /*amount of repititions*/
+ while(i + j + 1 < (unsigned)bitlen_lld.size && bitlen_lld.data[i + j + 1] == bitlen_lld.data[i]) j++;
+
+ if(bitlen_lld.data[i] == 0 && j >= 2) /*repeat code for zeroes*/
+ {
+ j++; /*include the first zero*/
+ if(j <= 10) /*repeat code 17 supports max 10 zeroes*/
+ {
+ uivector_push_back(&bitlen_lld_e, 17);
+ uivector_push_back(&bitlen_lld_e, j - 3);
+ }
+ else /*repeat code 18 supports max 138 zeroes*/
+ {
+ if(j > 138) j = 138;
+ uivector_push_back(&bitlen_lld_e, 18);
+ uivector_push_back(&bitlen_lld_e, j - 11);
+ }
+ i += (j - 1);
+ }
+ else if(j >= 3) /*repeat code for value other than zero*/
+ {
+ size_t k;
+ unsigned num = j / 6, rest = j % 6;
+ uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]);
+ for(k = 0; k < num; k++)
+ {
+ uivector_push_back(&bitlen_lld_e, 16);
+ uivector_push_back(&bitlen_lld_e, 6 - 3);
+ }
+ if(rest >= 3)
+ {
+ uivector_push_back(&bitlen_lld_e, 16);
+ uivector_push_back(&bitlen_lld_e, rest - 3);
+ }
+ else j -= rest;
+ i += j;
+ }
+ else /*too short to benefit from repeat code*/
+ {
+ uivector_push_back(&bitlen_lld_e, bitlen_lld.data[i]);
+ }
+ }
+
+ /*generate tree_cl, the huffmantree of huffmantrees*/
+
+ if(!uivector_resizev(&frequencies_cl, NUM_CODE_LENGTH_CODES, 0)) ERROR_BREAK(83 /*alloc fail*/);
+ for(i = 0; i < bitlen_lld_e.size; i++)
+ {
+ frequencies_cl.data[bitlen_lld_e.data[i]]++;
+ /*after a repeat code come the bits that specify the number of repetitions,
+ those don't need to be in the frequencies_cl calculation*/
+ if(bitlen_lld_e.data[i] >= 16) i++;
+ }
+
+ error = HuffmanTree_makeFromFrequencies(&tree_cl, frequencies_cl.data, frequencies_cl.size, 7);
+ if(error) break;
+
+ if(!uivector_resize(&bitlen_cl, NUM_CODE_LENGTH_CODES)) ERROR_BREAK(83 /*alloc fail*/);
+ for(i = 0; i < NUM_CODE_LENGTH_CODES; i++)
+ {
+ /*lenghts of code length tree is in the order as specified by deflate*/
+ bitlen_cl.data[i] = HuffmanTree_getLength(&tree_cl, CLCL_ORDER[i]);
+ }
+ while(bitlen_cl.data[bitlen_cl.size - 1] == 0 && bitlen_cl.size > 4)
+ {
+ /*remove zeros at the end, but minimum size must be 4*/
+ if(!uivector_resize(&bitlen_cl, bitlen_cl.size - 1)) ERROR_BREAK(83 /*alloc fail*/);
+ }
+ if(error) break;
+
+ /*
+ Write everything into the output
+
+ After the BFINAL and BTYPE, the dynamic block consists out of the following:
+ - 5 bits HLIT, 5 bits HDIST, 4 bits HCLEN
+ - (HCLEN+4)*3 bits code lengths of code length alphabet
+ - HLIT + 257 code lenghts of lit/length alphabet (encoded using the code length
+ alphabet, + possible repetition codes 16, 17, 18)
+ - HDIST + 1 code lengths of distance alphabet (encoded using the code length
+ alphabet, + possible repetition codes 16, 17, 18)
+ - compressed data
+ - 256 (end code)
+ */
+
+ /*Write block type*/
+ addBitToStream(bp, out, BFINAL);
+ addBitToStream(bp, out, 0); /*first bit of BTYPE "dynamic"*/
+ addBitToStream(bp, out, 1); /*second bit of BTYPE "dynamic"*/
+
+ /*write the HLIT, HDIST and HCLEN values*/
+ HLIT = (unsigned)(numcodes_ll - 257);
+ HDIST = (unsigned)(numcodes_d - 1);
+ HCLEN = (unsigned)bitlen_cl.size - 4;
+ addBitsToStream(bp, out, HLIT, 5);
+ addBitsToStream(bp, out, HDIST, 5);
+ addBitsToStream(bp, out, HCLEN, 4);
+
+ /*write the code lenghts of the code length alphabet*/
+ for(i = 0; i < HCLEN + 4; i++) addBitsToStream(bp, out, bitlen_cl.data[i], 3);
+
+ /*write the lenghts of the lit/len AND the dist alphabet*/
+ for(i = 0; i < bitlen_lld_e.size; i++)
+ {
+ addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_cl, bitlen_lld_e.data[i]),
+ HuffmanTree_getLength(&tree_cl, bitlen_lld_e.data[i]));
+ /*extra bits of repeat codes*/
+ if(bitlen_lld_e.data[i] == 16) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 2);
+ else if(bitlen_lld_e.data[i] == 17) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 3);
+ else if(bitlen_lld_e.data[i] == 18) addBitsToStream(bp, out, bitlen_lld_e.data[++i], 7);
+ }
+
+ /*write the compressed data symbols*/
+ writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d);
+ /*error: the length of the end code 256 must be larger than 0*/
+ if(HuffmanTree_getLength(&tree_ll, 256) == 0) ERROR_BREAK(64);
+
+ /*write the end code*/
+ addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256));
+
+ break; /*end of error-while*/
+ }
+
+ /*cleanup*/
+ uivector_cleanup(&lz77_encoded);
+ HuffmanTree_cleanup(&tree_ll);
+ HuffmanTree_cleanup(&tree_d);
+ HuffmanTree_cleanup(&tree_cl);
+ uivector_cleanup(&frequencies_ll);
+ uivector_cleanup(&frequencies_d);
+ uivector_cleanup(&frequencies_cl);
+ uivector_cleanup(&bitlen_lld_e);
+ uivector_cleanup(&bitlen_lld);
+ uivector_cleanup(&bitlen_cl);
+
+ return error;
+}
+
+static unsigned deflateFixed(ucvector* out, size_t* bp, Hash* hash,
+ const unsigned char* data,
+ size_t datapos, size_t dataend,
+ const LodePNGCompressSettings* settings, int final)
+{
+ HuffmanTree tree_ll; /*tree for literal values and length codes*/
+ HuffmanTree tree_d; /*tree for distance codes*/
+
+ unsigned BFINAL = final;
+ unsigned error = 0;
+ size_t i;
+
+ HuffmanTree_init(&tree_ll);
+ HuffmanTree_init(&tree_d);
+
+ generateFixedLitLenTree(&tree_ll);
+ generateFixedDistanceTree(&tree_d);
+
+ addBitToStream(bp, out, BFINAL);
+ addBitToStream(bp, out, 1); /*first bit of BTYPE*/
+ addBitToStream(bp, out, 0); /*second bit of BTYPE*/
+
+ if(settings->use_lz77) /*LZ77 encoded*/
+ {
+ uivector lz77_encoded;
+ uivector_init(&lz77_encoded);
+ error = encodeLZ77(&lz77_encoded, hash, data, datapos, dataend, settings->windowsize);
+ if(!error) writeLZ77data(bp, out, &lz77_encoded, &tree_ll, &tree_d);
+ uivector_cleanup(&lz77_encoded);
+ }
+ else /*no LZ77, but still will be Huffman compressed*/
+ {
+ for(i = datapos; i < dataend; i++)
+ {
+ addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, data[i]), HuffmanTree_getLength(&tree_ll, data[i]));
+ }
+ }
+ /*add END code*/
+ if(!error) addHuffmanSymbol(bp, out, HuffmanTree_getCode(&tree_ll, 256), HuffmanTree_getLength(&tree_ll, 256));
+
+ /*cleanup*/
+ HuffmanTree_cleanup(&tree_ll);
+ HuffmanTree_cleanup(&tree_d);
+
+ return error;
+}
+
+static unsigned lodepng_deflatev(ucvector* out, const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings* settings)
+{
+#if LODEPNG_CUSTOM_ZLIB_ENCODER == 2
+ if(settings->custom_encoder)
+ {
+ unsigned char** out2 = &out->data;
+ size_t* outsize = &out->size;
+
+ unsigned error = lodepng_custom_deflate(out2, outsize, in, insize, settings);
+
+ if(!error) ucvector_init_buffer(out, *out2, *outsize);
+ return error;
+ }
+ else
+ {
+#endif /*LODEPNG_CUSTOM_ZLIB_ENCODER == 2*/
+ unsigned error = 0;
+ size_t i, blocksize, numdeflateblocks;
+ size_t bp = 0; /*the bit pointer*/
+ Hash hash;
+
+ if(settings->btype > 2) return 61;
+
+ if(settings->btype == 0) return deflateNoCompression(out, in, insize);
+
+ if(settings->btype == 1) blocksize = insize;
+ else /*if(settings->btype == 2)*/
+ {
+ blocksize = insize / 8 + 8;
+ if(blocksize < 65535) blocksize = 65535;
+ }
+
+ numdeflateblocks = (insize + blocksize - 1) / blocksize;
+ if(numdeflateblocks == 0) numdeflateblocks = 1;
+
+ error = hash_init(&hash, settings->windowsize);
+ if(error) return error;
+
+ for(i = 0; i < numdeflateblocks && !error; i++)
+ {
+ int final = i == numdeflateblocks - 1;
+ size_t start = i * blocksize;
+ size_t end = start + blocksize;
+ if(end > insize) end = insize;
+
+ if(settings->btype == 1) error = deflateFixed(out, &bp, &hash, in, start, end, settings, final);
+ else if(settings->btype == 2) error = deflateDynamic(out, &bp, &hash, in, start, end, settings, final);
+ }
+
+ hash_cleanup(&hash);
+
+ return error;
+#if LODEPNG_CUSTOM_ZLIB_ENCODER == 2
+ }
+#endif /*LODEPNG_CUSTOM_ZLIB_ENCODER == 2*/
+}
+
+unsigned lodepng_deflate(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings* settings)
+{
+ unsigned error;
+ ucvector v;
+ ucvector_init_buffer(&v, *out, *outsize);
+ error = lodepng_deflatev(&v, in, insize, settings);
+ *out = v.data;
+ *outsize = v.size;
+ return error;
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Adler32 */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+static unsigned update_adler32(unsigned adler, const unsigned char* data, unsigned len)
+{
+ unsigned s1 = adler & 0xffff;
+ unsigned s2 = (adler >> 16) & 0xffff;
+
+ while(len > 0)
+ {
+ /*at least 5550 sums can be done before the sums overflow, saving a lot of module divisions*/
+ unsigned amount = len > 5550 ? 5550 : len;
+ len -= amount;
+ while(amount > 0)
+ {
+ s1 = (s1 + *data++);
+ s2 = (s2 + s1);
+ amount--;
+ }
+ s1 %= 65521;
+ s2 %= 65521;
+ }
+
+ return (s2 << 16) | s1;
+}
+
+/*Return the adler32 of the bytes data[0..len-1]*/
+static unsigned adler32(const unsigned char* data, unsigned len)
+{
+ return update_adler32(1L, data, len);
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Zlib / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
+ size_t insize, const LodePNGDecompressSettings* settings)
+{
+#if LODEPNG_CUSTOM_ZLIB_DECODER == 1
+ if(settings->custom_decoder)
+ {
+ return lodepng_custom_zlib_decompress(out, outsize, in, insize, settings);
+ }
+ else
+ {
+#endif /*LODEPNG_CUSTOM_ZLIB_DECODER == 1*/
+ unsigned error = 0;
+ unsigned CM, CINFO, FDICT;
+
+ if(insize < 2) return 53; /*error, size of zlib data too small*/
+ /*read information from zlib header*/
+ if((in[0] * 256 + in[1]) % 31 != 0)
+ {
+ /*error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way*/
+ return 24;
+ }
+
+ CM = in[0] & 15;
+ CINFO = (in[0] >> 4) & 15;
+ /*FCHECK = in[1] & 31;*/ /*FCHECK is already tested above*/
+ FDICT = (in[1] >> 5) & 1;
+ /*FLEVEL = (in[1] >> 6) & 3;*/ /*FLEVEL is not used here*/
+
+ if(CM != 8 || CINFO > 7)
+ {
+ /*error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec*/
+ return 25;
+ }
+ if(FDICT != 0)
+ {
+ /*error: the specification of PNG says about the zlib stream:
+ "The additional flags shall not specify a preset dictionary."*/
+ return 26;
+ }
+
+ error = lodepng_inflate(out, outsize, in + 2, insize - 2, settings);
+ if(error) return error;
+
+ if(!settings->ignore_adler32)
+ {
+ unsigned ADLER32 = lodepng_read32bitInt(&in[insize - 4]);
+ unsigned checksum = adler32(*out, (unsigned)(*outsize));
+ if(checksum != ADLER32) return 58; /*error, adler checksum not correct, data must be corrupted*/
+ }
+
+ return 0; /*no error*/
+#if LODEPNG_CUSTOM_ZLIB_DECODER == 1
+ }
+#endif /*LODEPNG_CUSTOM_ZLIB_DECODER == 1*/
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
+ size_t insize, const LodePNGCompressSettings* settings)
+{
+#if LODEPNG_CUSTOM_ZLIB_ENCODER == 1
+ if(settings->custom_encoder)
+ {
+ return lodepng_custom_zlib_compress(out, outsize, in, insize, settings);
+ }
+ else
+ {
+#endif /*LODEPNG_CUSTOM_ZLIB_ENCODER == 1*/
+ /*initially, *out must be NULL and outsize 0, if you just give some random *out
+ that's pointing to a non allocated buffer, this'll crash*/
+ ucvector deflatedata, outv;
+ size_t i;
+ unsigned error;
+
+ unsigned ADLER32;
+ /*zlib data: 1 byte CMF (CM+CINFO), 1 byte FLG, deflate data, 4 byte ADLER32 checksum of the Decompressed data*/
+ unsigned CMF = 120; /*0b01111000: CM 8, CINFO 7. With CINFO 7, any window size up to 32768 can be used.*/
+ unsigned FLEVEL = 0;
+ unsigned FDICT = 0;
+ unsigned CMFFLG = 256 * CMF + FDICT * 32 + FLEVEL * 64;
+ unsigned FCHECK = 31 - CMFFLG % 31;
+ CMFFLG += FCHECK;
+
+ /*ucvector-controlled version of the output buffer, for dynamic array*/
+ ucvector_init_buffer(&outv, *out, *outsize);
+
+ ucvector_push_back(&outv, (unsigned char)(CMFFLG / 256));
+ ucvector_push_back(&outv, (unsigned char)(CMFFLG % 256));
+
+ ucvector_init(&deflatedata);
+ error = lodepng_deflatev(&deflatedata, in, insize, settings);
+
+ if(!error)
+ {
+ ADLER32 = adler32(in, (unsigned)insize);
+ for(i = 0; i < deflatedata.size; i++) ucvector_push_back(&outv, deflatedata.data[i]);
+ ucvector_cleanup(&deflatedata);
+ lodepng_add32bitInt(&outv, ADLER32);
+ }
+
+ *out = outv.data;
+ *outsize = outv.size;
+
+ return error;
+#if LODEPNG_CUSTOM_ZLIB_ENCODER == 1
+ }
+#endif /*LODEPNG_CUSTOM_ZLIB_ENCODER == 1*/
+}
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#else /*no LODEPNG_COMPILE_ZLIB*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+static unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize, const unsigned char* in,
+ size_t insize, const LodePNGDecompressSettings* settings)
+{
+ return lodepng_custom_zlib_decompress(out, outsize, in, insize, settings);
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+#ifdef LODEPNG_COMPILE_ENCODER
+static unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize, const unsigned char* in,
+ size_t insize, const LodePNGCompressSettings* settings)
+{
+ return lodepng_custom_zlib_compress(out, outsize, in, insize, settings);
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/*this is a good tradeoff between speed and compression ratio*/
+#define DEFAULT_WINDOWSIZE 2048
+
+void lodepng_compress_settings_init(LodePNGCompressSettings* settings)
+{
+ /*compress with dynamic huffman tree (not in the mathematical sense, just not the predefined one)*/
+ settings->btype = 2;
+ settings->use_lz77 = 1;
+ settings->windowsize = DEFAULT_WINDOWSIZE;
+#if LODEPNG_CUSTOM_ZLIB_ENCODER == 0
+ settings->custom_encoder = 0;
+#else
+ settings->custom_encoder = 1;
+#endif
+}
+
+#if LODEPNG_CUSTOM_ZLIB_ENCODER == 0
+const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 0};
+#else
+const LodePNGCompressSettings lodepng_default_compress_settings = {2, 1, DEFAULT_WINDOWSIZE, 1};
+#endif
+
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings)
+{
+ settings->ignore_adler32 = 0;
+#if LODEPNG_CUSTOM_ZLIB_DECODER == 0
+ settings->custom_decoder = 0;
+#else
+ settings->custom_decoder = 1;
+#endif
+}
+
+#if LODEPNG_CUSTOM_ZLIB_DECODER == 0
+const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 0};
+#else
+const LodePNGDecompressSettings lodepng_default_decompress_settings = {0, 1};
+#endif
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // End of Zlib related code. Begin of PNG related code. // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+#ifdef LODEPNG_COMPILE_PNG
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / CRC32 / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+static unsigned Crc32_crc_table_computed = 0;
+static unsigned Crc32_crc_table[256];
+
+/*Make the table for a fast CRC.*/
+static void Crc32_make_crc_table(void)
+{
+ unsigned c, k, n;
+ for(n = 0; n < 256; n++)
+ {
+ c = n;
+ for(k = 0; k < 8; k++)
+ {
+ if(c & 1) c = 0xedb88320L ^ (c >> 1);
+ else c = c >> 1;
+ }
+ Crc32_crc_table[n] = c;
+ }
+ Crc32_crc_table_computed = 1;
+}
+
+/*Update a running CRC with the bytes buf[0..len-1]--the CRC should be
+initialized to all 1's, and the transmitted value is the 1's complement of the
+final running CRC (see the crc() routine below).*/
+static unsigned Crc32_update_crc(const unsigned char* buf, unsigned crc, size_t len)
+{
+ unsigned c = crc;
+ size_t n;
+
+ if(!Crc32_crc_table_computed) Crc32_make_crc_table();
+ for(n = 0; n < len; n++)
+ {
+ c = Crc32_crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
+ }
+ return c;
+}
+
+/*Return the CRC of the bytes buf[0..len-1].*/
+unsigned lodepng_crc32(const unsigned char* buf, size_t len)
+{
+ return Crc32_update_crc(buf, 0xffffffffL, len) ^ 0xffffffffL;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Reading and writing single bits and bytes from/to stream for LodePNG / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+static unsigned char readBitFromReversedStream(size_t* bitpointer, const unsigned char* bitstream)
+{
+ unsigned char result = (unsigned char)((bitstream[(*bitpointer) >> 3] >> (7 - ((*bitpointer) & 0x7))) & 1);
+ (*bitpointer)++;
+ return result;
+}
+
+static unsigned readBitsFromReversedStream(size_t* bitpointer, const unsigned char* bitstream, size_t nbits)
+{
+ unsigned result = 0;
+ size_t i;
+ for(i = nbits - 1; i < nbits; i--)
+ {
+ result += (unsigned)readBitFromReversedStream(bitpointer, bitstream) << i;
+ }
+ return result;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+static void setBitOfReversedStream0(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
+{
+ /*the current bit in bitstream must be 0 for this to work*/
+ if(bit)
+ {
+ /*earlier bit of huffman code is in a lesser significant bit of an earlier byte*/
+ bitstream[(*bitpointer) >> 3] |= (bit << (7 - ((*bitpointer) & 0x7)));
+ }
+ (*bitpointer)++;
+}
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+static void setBitOfReversedStream(size_t* bitpointer, unsigned char* bitstream, unsigned char bit)
+{
+ /*the current bit in bitstream may be 0 or 1 for this to work*/
+ if(bit == 0) bitstream[(*bitpointer) >> 3] &= (unsigned char)(~(1 << (7 - ((*bitpointer) & 0x7))));
+ else bitstream[(*bitpointer) >> 3] |= (1 << (7 - ((*bitpointer) & 0x7)));
+ (*bitpointer)++;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / PNG chunks / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+unsigned lodepng_chunk_length(const unsigned char* chunk)
+{
+ return lodepng_read32bitInt(&chunk[0]);
+}
+
+void lodepng_chunk_type(char type[5], const unsigned char* chunk)
+{
+ unsigned i;
+ for(i = 0; i < 4; i++) type[i] = chunk[4 + i];
+ type[4] = 0; /*null termination char*/
+}
+
+unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type)
+{
+ if(strlen(type) != 4) return 0;
+ return (chunk[4] == type[0] && chunk[5] == type[1] && chunk[6] == type[2] && chunk[7] == type[3]);
+}
+
+unsigned char lodepng_chunk_ancillary(const unsigned char* chunk)
+{
+ return((chunk[4] & 32) != 0);
+}
+
+unsigned char lodepng_chunk_private(const unsigned char* chunk)
+{
+ return((chunk[6] & 32) != 0);
+}
+
+unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk)
+{
+ return((chunk[7] & 32) != 0);
+}
+
+unsigned char* lodepng_chunk_data(unsigned char* chunk)
+{
+ return &chunk[8];
+}
+
+const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk)
+{
+ return &chunk[8];
+}
+
+unsigned lodepng_chunk_check_crc(const unsigned char* chunk)
+{
+ unsigned length = lodepng_chunk_length(chunk);
+ unsigned CRC = lodepng_read32bitInt(&chunk[length + 8]);
+ /*the CRC is taken of the data and the 4 chunk type letters, not the length*/
+ unsigned checksum = lodepng_crc32(&chunk[4], length + 4);
+ if(CRC != checksum) return 1;
+ else return 0;
+}
+
+void lodepng_chunk_generate_crc(unsigned char* chunk)
+{
+ unsigned length = lodepng_chunk_length(chunk);
+ unsigned CRC = lodepng_crc32(&chunk[4], length + 4);
+ lodepng_set32bitInt(chunk + 8 + length, CRC);
+}
+
+unsigned char* lodepng_chunk_next(unsigned char* chunk)
+{
+ unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
+ return &chunk[total_chunk_length];
+}
+
+const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk)
+{
+ unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
+ return &chunk[total_chunk_length];
+}
+
+unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk)
+{
+ unsigned i;
+ unsigned total_chunk_length = lodepng_chunk_length(chunk) + 12;
+ unsigned char *chunk_start, *new_buffer;
+ size_t new_length = (*outlength) + total_chunk_length;
+ if(new_length < total_chunk_length || new_length < (*outlength)) return 77; /*integer overflow happened*/
+
+ new_buffer = (unsigned char*)myrealloc(*out, new_length);
+ if(!new_buffer) return 83; /*alloc fail*/
+ (*out) = new_buffer;
+ (*outlength) = new_length;
+ chunk_start = &(*out)[new_length - total_chunk_length];
+
+ for(i = 0; i < total_chunk_length; i++) chunk_start[i] = chunk[i];
+
+ return 0;
+}
+
+unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length,
+ const char* type, const unsigned char* data)
+{
+ unsigned i;
+ unsigned char *chunk, *new_buffer;
+ size_t new_length = (*outlength) + length + 12;
+ if(new_length < length + 12 || new_length < (*outlength)) return 77; /*integer overflow happened*/
+ new_buffer = (unsigned char*)myrealloc(*out, new_length);
+ if(!new_buffer) return 83; /*alloc fail*/
+ (*out) = new_buffer;
+ (*outlength) = new_length;
+ chunk = &(*out)[(*outlength) - length - 12];
+
+ /*1: length*/
+ lodepng_set32bitInt(chunk, (unsigned)length);
+
+ /*2: chunk name (4 letters)*/
+ chunk[4] = type[0];
+ chunk[5] = type[1];
+ chunk[6] = type[2];
+ chunk[7] = type[3];
+
+ /*3: the data*/
+ for(i = 0; i < length; i++) chunk[8 + i] = data[i];
+
+ /*4: CRC (of the chunkname characters and the data)*/
+ lodepng_chunk_generate_crc(chunk);
+
+ return 0;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / Color types and such / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*return type is a LodePNG error code*/
+static unsigned checkColorValidity(LodePNGColorType colortype, unsigned bd) /*bd = bitdepth*/
+{
+ switch(colortype)
+ {
+ case 0: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; break; /*grey*/
+ case 2: if(!( bd == 8 || bd == 16)) return 37; break; /*RGB*/
+ case 3: if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; break; /*palette*/
+ case 4: if(!( bd == 8 || bd == 16)) return 37; break; /*grey + alpha*/
+ case 6: if(!( bd == 8 || bd == 16)) return 37; break; /*RGBA*/
+ default: return 31;
+ }
+ return 0; /*allowed color type / bits combination*/
+}
+
+static unsigned getNumColorChannels(LodePNGColorType colortype)
+{
+ switch(colortype)
+ {
+ case 0: return 1; /*grey*/
+ case 2: return 3; /*RGB*/
+ case 3: return 1; /*palette*/
+ case 4: return 2; /*grey + alpha*/
+ case 6: return 4; /*RGBA*/
+ }
+ return 0; /*unexisting color type*/
+}
+
+static unsigned lodepng_get_bpp_lct(LodePNGColorType colortype, unsigned bitdepth)
+{
+ /*bits per pixel is amount of channels * bits per channel*/
+ return getNumColorChannels(colortype) * bitdepth;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+void lodepng_color_mode_init(LodePNGColorMode* info)
+{
+ info->key_defined = 0;
+ info->key_r = info->key_g = info->key_b = 0;
+ info->colortype = LCT_RGBA;
+ info->bitdepth = 8;
+ info->palette = 0;
+ info->palettesize = 0;
+}
+
+void lodepng_color_mode_cleanup(LodePNGColorMode* info)
+{
+ lodepng_palette_clear(info);
+}
+
+unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source)
+{
+ size_t i;
+ lodepng_color_mode_cleanup(dest);
+ *dest = *source;
+ if(source->palette)
+ {
+ dest->palette = (unsigned char*)mymalloc(source->palettesize * 4);
+ if(!dest->palette && source->palettesize) return 83; /*alloc fail*/
+ for(i = 0; i < source->palettesize * 4; i++) dest->palette[i] = source->palette[i];
+ }
+ return 0;
+}
+
+static int lodepng_color_mode_equal(const LodePNGColorMode* a, const LodePNGColorMode* b)
+{
+ size_t i;
+ if(a->colortype != b->colortype) return 0;
+ if(a->bitdepth != b->bitdepth) return 0;
+ if(a->key_defined != b->key_defined) return 0;
+ if(a->key_defined)
+ {
+ if(a->key_r != b->key_r) return 0;
+ if(a->key_g != b->key_g) return 0;
+ if(a->key_b != b->key_b) return 0;
+ }
+ if(a->palettesize != b->palettesize) return 0;
+ for(i = 0; i < a->palettesize * 4; i++)
+ {
+ if(a->palette[i] != b->palette[i]) return 0;
+ }
+ return 1;
+}
+
+void lodepng_palette_clear(LodePNGColorMode* info)
+{
+ if(info->palette) myfree(info->palette);
+ info->palettesize = 0;
+}
+
+unsigned lodepng_palette_add(LodePNGColorMode* info,
+ unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ unsigned char* data;
+ /*the same resize technique as C++ std::vectors is used, and here it's made so that for a palette with
+ the max of 256 colors, it'll have the exact alloc size*/
+ if(!(info->palettesize & (info->palettesize - 1))) /*if palettesize is 0 or a power of two*/
+ {
+ /*allocated data must be at least 4* palettesize (for 4 color bytes)*/
+ size_t alloc_size = info->palettesize == 0 ? 4 : info->palettesize * 4 * 2;
+ data = (unsigned char*)myrealloc(info->palette, alloc_size);
+ if(!data) return 83; /*alloc fail*/
+ else info->palette = data;
+ }
+ info->palette[4 * info->palettesize + 0] = r;
+ info->palette[4 * info->palettesize + 1] = g;
+ info->palette[4 * info->palettesize + 2] = b;
+ info->palette[4 * info->palettesize + 3] = a;
+ info->palettesize++;
+ return 0;
+}
+
+unsigned lodepng_get_bpp(const LodePNGColorMode* info)
+{
+ /*calculate bits per pixel out of colortype and bitdepth*/
+ return lodepng_get_bpp_lct(info->colortype, info->bitdepth);
+}
+
+unsigned lodepng_get_channels(const LodePNGColorMode* info)
+{
+ return getNumColorChannels(info->colortype);
+}
+
+unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info)
+{
+ return info->colortype == LCT_GREY || info->colortype == LCT_GREY_ALPHA;
+}
+
+unsigned lodepng_is_alpha_type(const LodePNGColorMode* info)
+{
+ return (info->colortype & 4) != 0; /*4 or 6*/
+}
+
+unsigned lodepng_is_palette_type(const LodePNGColorMode* info)
+{
+ return info->colortype == LCT_PALETTE;
+}
+
+unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info)
+{
+ size_t i;
+ for(i = 0; i < info->palettesize; i++)
+ {
+ if(info->palette[i * 4 + 3] < 255) return 1;
+ }
+ return 0;
+}
+
+unsigned lodepng_can_have_alpha(const LodePNGColorMode* info)
+{
+ return info->key_defined
+ || lodepng_is_alpha_type(info)
+ || lodepng_has_palette_alpha(info);
+}
+
+size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color)
+{
+ return (w * h * lodepng_get_bpp(color) + 7) / 8;
+}
+
+size_t lodepng_get_raw_size_lct(unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth)
+{
+ return (w * h * lodepng_get_bpp_lct(colortype, bitdepth) + 7) / 8;
+}
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+
+static void LodePNGUnknownChunks_init(LodePNGInfo* info)
+{
+ unsigned i;
+ for(i = 0; i < 3; i++) info->unknown_chunks_data[i] = 0;
+ for(i = 0; i < 3; i++) info->unknown_chunks_size[i] = 0;
+}
+
+static void LodePNGUnknownChunks_cleanup(LodePNGInfo* info)
+{
+ unsigned i;
+ for(i = 0; i < 3; i++) myfree(info->unknown_chunks_data[i]);
+}
+
+static unsigned LodePNGUnknownChunks_copy(LodePNGInfo* dest, const LodePNGInfo* src)
+{
+ unsigned i;
+
+ LodePNGUnknownChunks_cleanup(dest);
+
+ for(i = 0; i < 3; i++)
+ {
+ size_t j;
+ dest->unknown_chunks_size[i] = src->unknown_chunks_size[i];
+ dest->unknown_chunks_data[i] = (unsigned char*)mymalloc(src->unknown_chunks_size[i]);
+ if(!dest->unknown_chunks_data[i] && dest->unknown_chunks_size[i]) return 83; /*alloc fail*/
+ for(j = 0; j < src->unknown_chunks_size[i]; j++)
+ {
+ dest->unknown_chunks_data[i][j] = src->unknown_chunks_data[i][j];
+ }
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static void LodePNGText_init(LodePNGInfo* info)
+{
+ info->text_num = 0;
+ info->text_keys = NULL;
+ info->text_strings = NULL;
+}
+
+static void LodePNGText_cleanup(LodePNGInfo* info)
+{
+ size_t i;
+ for(i = 0; i < info->text_num; i++)
+ {
+ string_cleanup(&info->text_keys[i]);
+ string_cleanup(&info->text_strings[i]);
+ }
+ myfree(info->text_keys);
+ myfree(info->text_strings);
+}
+
+static unsigned LodePNGText_copy(LodePNGInfo* dest, const LodePNGInfo* source)
+{
+ size_t i = 0;
+ dest->text_keys = 0;
+ dest->text_strings = 0;
+ dest->text_num = 0;
+ for(i = 0; i < source->text_num; i++)
+ {
+ CERROR_TRY_RETURN(lodepng_add_text(dest, source->text_keys[i], source->text_strings[i]));
+ }
+ return 0;
+}
+
+void lodepng_clear_text(LodePNGInfo* info)
+{
+ LodePNGText_cleanup(info);
+}
+
+unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str)
+{
+ char** new_keys = (char**)(myrealloc(info->text_keys, sizeof(char*) * (info->text_num + 1)));
+ char** new_strings = (char**)(myrealloc(info->text_strings, sizeof(char*) * (info->text_num + 1)));
+ if(!new_keys || !new_strings)
+ {
+ myfree(new_keys);
+ myfree(new_strings);
+ return 83; /*alloc fail*/
+ }
+
+ info->text_num++;
+ info->text_keys = new_keys;
+ info->text_strings = new_strings;
+
+ string_init(&info->text_keys[info->text_num - 1]);
+ string_set(&info->text_keys[info->text_num - 1], key);
+
+ string_init(&info->text_strings[info->text_num - 1]);
+ string_set(&info->text_strings[info->text_num - 1], str);
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static void LodePNGIText_init(LodePNGInfo* info)
+{
+ info->itext_num = 0;
+ info->itext_keys = NULL;
+ info->itext_langtags = NULL;
+ info->itext_transkeys = NULL;
+ info->itext_strings = NULL;
+}
+
+static void LodePNGIText_cleanup(LodePNGInfo* info)
+{
+ size_t i;
+ for(i = 0; i < info->itext_num; i++)
+ {
+ string_cleanup(&info->itext_keys[i]);
+ string_cleanup(&info->itext_langtags[i]);
+ string_cleanup(&info->itext_transkeys[i]);
+ string_cleanup(&info->itext_strings[i]);
+ }
+ myfree(info->itext_keys);
+ myfree(info->itext_langtags);
+ myfree(info->itext_transkeys);
+ myfree(info->itext_strings);
+}
+
+static unsigned LodePNGIText_copy(LodePNGInfo* dest, const LodePNGInfo* source)
+{
+ size_t i = 0;
+ dest->itext_keys = 0;
+ dest->itext_langtags = 0;
+ dest->itext_transkeys = 0;
+ dest->itext_strings = 0;
+ dest->itext_num = 0;
+ for(i = 0; i < source->itext_num; i++)
+ {
+ CERROR_TRY_RETURN(lodepng_add_itext(dest, source->itext_keys[i], source->itext_langtags[i],
+ source->itext_transkeys[i], source->itext_strings[i]));
+ }
+ return 0;
+}
+
+void lodepng_clear_itext(LodePNGInfo* info)
+{
+ LodePNGIText_cleanup(info);
+}
+
+unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag,
+ const char* transkey, const char* str)
+{
+ char** new_keys = (char**)(myrealloc(info->itext_keys, sizeof(char*) * (info->itext_num + 1)));
+ char** new_langtags = (char**)(myrealloc(info->itext_langtags, sizeof(char*) * (info->itext_num + 1)));
+ char** new_transkeys = (char**)(myrealloc(info->itext_transkeys, sizeof(char*) * (info->itext_num + 1)));
+ char** new_strings = (char**)(myrealloc(info->itext_strings, sizeof(char*) * (info->itext_num + 1)));
+ if(!new_keys || !new_langtags || !new_transkeys || !new_strings)
+ {
+ myfree(new_keys);
+ myfree(new_langtags);
+ myfree(new_transkeys);
+ myfree(new_strings);
+ return 83; /*alloc fail*/
+ }
+
+ info->itext_num++;
+ info->itext_keys = new_keys;
+ info->itext_langtags = new_langtags;
+ info->itext_transkeys = new_transkeys;
+ info->itext_strings = new_strings;
+
+ string_init(&info->itext_keys[info->itext_num - 1]);
+ string_set(&info->itext_keys[info->itext_num - 1], key);
+
+ string_init(&info->itext_langtags[info->itext_num - 1]);
+ string_set(&info->itext_langtags[info->itext_num - 1], langtag);
+
+ string_init(&info->itext_transkeys[info->itext_num - 1]);
+ string_set(&info->itext_transkeys[info->itext_num - 1], transkey);
+
+ string_init(&info->itext_strings[info->itext_num - 1]);
+ string_set(&info->itext_strings[info->itext_num - 1], str);
+
+ return 0;
+}
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+void lodepng_info_init(LodePNGInfo* info)
+{
+ lodepng_color_mode_init(&info->color);
+ info->interlace_method = 0;
+ info->compression_method = 0;
+ info->filter_method = 0;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ info->background_defined = 0;
+ info->background_r = info->background_g = info->background_b = 0;
+
+ LodePNGText_init(info);
+ LodePNGIText_init(info);
+
+ info->time_defined = 0;
+ info->phys_defined = 0;
+
+ LodePNGUnknownChunks_init(info);
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+}
+
+void lodepng_info_cleanup(LodePNGInfo* info)
+{
+ lodepng_color_mode_cleanup(&info->color);
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ LodePNGText_cleanup(info);
+ LodePNGIText_cleanup(info);
+
+ LodePNGUnknownChunks_cleanup(info);
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+}
+
+unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source)
+{
+ lodepng_info_cleanup(dest);
+ *dest = *source;
+ lodepng_color_mode_init(&dest->color);
+ CERROR_TRY_RETURN(lodepng_color_mode_copy(&dest->color, &source->color));
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ CERROR_TRY_RETURN(LodePNGText_copy(dest, source));
+ CERROR_TRY_RETURN(LodePNGIText_copy(dest, source));
+
+ LodePNGUnknownChunks_init(dest);
+ CERROR_TRY_RETURN(LodePNGUnknownChunks_copy(dest, source));
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ return 0;
+}
+
+void lodepng_info_swap(LodePNGInfo* a, LodePNGInfo* b)
+{
+ LodePNGInfo temp = *a;
+ *a = *b;
+ *b = temp;
+}
+
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*index: bitgroup index, bits: bitgroup size(1, 2 or 4, in: bitgroup value, out: octet array to add bits to*/
+static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in)
+{
+ /*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/
+ unsigned p = index % (8 / bits);
+ in &= (1 << bits) - 1; /*filter out any other bits of the input value*/
+ in = in << (bits * (8 / bits - p - 1));
+ if(p == 0) out[index * bits / 8] = in;
+ else out[index * bits / 8] |= in;
+}
+
+typedef struct ColorTree ColorTree;
+
+/*
+One node of a color tree
+This is the data structure used to count the number of unique colors and to get a palette
+index for a color. It's a bit like an octree for RGB bits, except that a node has 256
+children and there is one level of the tree per color channel. This may use more memory
+than an octree, but this is only used to count up to 256 so it's good enough.
+*/
+struct ColorTree
+{
+ ColorTree* next; /*null, or array of 256 pointers to ColorTree of next level*/
+ int index; /*the payload. Only has a meaningful value if this is in the 4th level*/
+};
+
+static void color_tree_make_next(ColorTree* tree);
+
+/*next: whether to create the next array or not*/
+static void color_tree_init(ColorTree* tree, int next)
+{
+ if(next) color_tree_make_next(tree);
+ else tree->next = 0;
+ tree->index = -1;
+}
+
+static void color_tree_make_next(ColorTree* tree)
+{
+ int i;
+ tree->next = (ColorTree*)mymalloc(256 * sizeof(ColorTree));
+ for(i = 0; i < 256; i++) color_tree_init(&tree->next[i], 0);
+}
+
+static void color_tree_cleanup(ColorTree* tree)
+{
+ if(tree->next)
+ {
+ int i;
+ for(i = 0; i < 256; i++) color_tree_cleanup(&tree->next[i]);
+ myfree(tree->next);
+ }
+}
+
+/*returns -1 if color not present, its index otherwise*/
+static int color_tree_get(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ tree = &tree->next[r];
+ if(tree->next == 0) return -1;
+ tree = &tree->next[g];
+ if(tree->next == 0) return -1;
+ tree = &tree->next[b];
+ if(tree->next == 0) return -1;
+ tree = &tree->next[a];
+
+ return tree->index;
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+static int color_tree_has(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ return color_tree_get(tree, r, g, b, a) >= 0;
+}
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/*color is not allowed to already exist. Index should be >= 0 (it's signed to be compatible with using -1 for "doesn't exist")*/
+static void color_tree_add(ColorTree* tree, unsigned char r, unsigned char g, unsigned char b, unsigned char a, int index)
+{
+ tree = &tree->next[r];
+ if(tree->next == 0) color_tree_make_next(tree);
+ tree = &tree->next[g];
+ if(tree->next == 0) color_tree_make_next(tree);
+ tree = &tree->next[b];
+ if(tree->next == 0) color_tree_make_next(tree);
+ tree = &tree->next[a];
+
+ tree->index = index;
+}
+
+/*put a pixel, given its RGBA color, into image of any color type*/
+static unsigned rgba8ToPixel(unsigned char* out, size_t i,
+ const LodePNGColorMode* mode, ColorTree* tree /*for palette*/,
+ unsigned char r, unsigned char g, unsigned char b, unsigned char a)
+{
+ if(mode->colortype == LCT_GREY)
+ {
+ unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/;
+ if(mode->bitdepth == 8) out[i] = grey;
+ else if(mode->bitdepth == 16) out[i * 2 + 0] = out[i * 2 + 1] = grey;
+ else
+ {
+ /*take the most significant bits of grey*/
+ grey = (grey >> (8 - mode->bitdepth)) & ((1 << mode->bitdepth) - 1);
+ addColorBits(out, i, mode->bitdepth, grey);
+ }
+ }
+ else if(mode->colortype == LCT_RGB)
+ {
+ if(mode->bitdepth == 8)
+ {
+ out[i * 3 + 0] = r;
+ out[i * 3 + 1] = g;
+ out[i * 3 + 2] = b;
+ }
+ else
+ {
+ out[i * 6 + 0] = out[i * 6 + 1] = r;
+ out[i * 6 + 2] = out[i * 6 + 3] = g;
+ out[i * 6 + 4] = out[i * 6 + 5] = b;
+ }
+ }
+ else if(mode->colortype == LCT_PALETTE)
+ {
+ int index = color_tree_get(tree, r, g, b, a);
+ if(index < 0) return 82; /*color not in palette*/
+ if(mode->bitdepth == 8) out[i] = index;
+ else addColorBits(out, i, mode->bitdepth, index);
+ }
+ else if(mode->colortype == LCT_GREY_ALPHA)
+ {
+ unsigned char grey = r; /*((unsigned short)r + g + b) / 3*/;
+ if(mode->bitdepth == 8)
+ {
+ out[i * 2 + 0] = grey;
+ out[i * 2 + 1] = a;
+ }
+ else if(mode->bitdepth == 16)
+ {
+ out[i * 4 + 0] = out[i * 4 + 1] = grey;
+ out[i * 4 + 2] = out[i * 4 + 3] = a;
+ }
+ }
+ else if(mode->colortype == LCT_RGBA)
+ {
+ if(mode->bitdepth == 8)
+ {
+ out[i * 4 + 0] = r;
+ out[i * 4 + 1] = g;
+ out[i * 4 + 2] = b;
+ out[i * 4 + 3] = a;
+ }
+ else
+ {
+ out[i * 8 + 0] = out[i * 8 + 1] = r;
+ out[i * 8 + 2] = out[i * 8 + 3] = g;
+ out[i * 8 + 4] = out[i * 8 + 5] = b;
+ out[i * 8 + 6] = out[i * 8 + 7] = a;
+ }
+ }
+
+ return 0; /*no error*/
+}
+
+/*put a pixel, given its RGBA16 color, into image of any color 16-bitdepth type*/
+static unsigned rgba16ToPixel(unsigned char* out, size_t i,
+ const LodePNGColorMode* mode,
+ unsigned short r, unsigned short g, unsigned short b, unsigned short a)
+{
+ if(mode->bitdepth != 16) return 85; /*must be 16 for this function*/
+ if(mode->colortype == LCT_GREY)
+ {
+ unsigned short grey = r; /*((unsigned)r + g + b) / 3*/;
+ out[i * 2 + 0] = (grey >> 8) & 255;
+ out[i * 2 + 1] = grey & 255;
+ }
+ else if(mode->colortype == LCT_RGB)
+ {
+ out[i * 6 + 0] = (r >> 8) & 255;
+ out[i * 6 + 1] = r & 255;
+ out[i * 6 + 2] = (g >> 8) & 255;
+ out[i * 6 + 3] = g & 255;
+ out[i * 6 + 4] = (b >> 8) & 255;
+ out[i * 6 + 5] = b & 255;
+ }
+ else if(mode->colortype == LCT_GREY_ALPHA)
+ {
+ unsigned short grey = r; /*((unsigned)r + g + b) / 3*/;
+ out[i * 4 + 0] = (grey >> 8) & 255;
+ out[i * 4 + 1] = grey & 255;
+ out[i * 4 + 2] = (a >> 8) & 255;
+ out[i * 4 + 3] = a & 255;
+ }
+ else if(mode->colortype == LCT_RGBA)
+ {
+ out[i * 8 + 0] = (r >> 8) & 255;
+ out[i * 8 + 1] = r & 255;
+ out[i * 8 + 2] = (g >> 8) & 255;
+ out[i * 8 + 3] = g & 255;
+ out[i * 8 + 4] = (b >> 8) & 255;
+ out[i * 8 + 5] = b & 255;
+ out[i * 8 + 6] = (a >> 8) & 255;
+ out[i * 8 + 7] = a & 255;
+ }
+
+ return 0; /*no error*/
+}
+
+/*Get RGBA8 color of pixel with index i (y * width + x) from the raw image with given color type.*/
+static unsigned getPixelColorRGBA8(unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a,
+ const unsigned char* in, size_t i, const LodePNGColorMode* mode)
+{
+ if(mode->colortype == LCT_GREY)
+ {
+ if(mode->bitdepth == 8)
+ {
+ *r = *g = *b = in[i];
+ if(mode->key_defined && *r == mode->key_r) *a = 0;
+ else *a = 255;
+ }
+ else if(mode->bitdepth == 16)
+ {
+ *r = *g = *b = in[i * 2 + 0];
+ if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
+ else *a = 255;
+ }
+ else
+ {
+ unsigned highest = ((1U << mode->bitdepth) - 1U); /*highest possible value for this bit depth*/
+ size_t j = i * mode->bitdepth;
+ unsigned value = readBitsFromReversedStream(&j, in, mode->bitdepth);
+ *r = *g = *b = (value * 255) / highest;
+ if(mode->key_defined && value == mode->key_r) *a = 0;
+ else *a = 255;
+ }
+ }
+ else if(mode->colortype == LCT_RGB)
+ {
+ if(mode->bitdepth == 8)
+ {
+ *r = in[i * 3 + 0]; *g = in[i * 3 + 1]; *b = in[i * 3 + 2];
+ if(mode->key_defined && *r == mode->key_r && *g == mode->key_g && *b == mode->key_b) *a = 0;
+ else *a = 255;
+ }
+ else
+ {
+ *r = in[i * 6 + 0];
+ *g = in[i * 6 + 2];
+ *b = in[i * 6 + 4];
+ if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
+ && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
+ && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
+ else *a = 255;
+ }
+ }
+ else if(mode->colortype == LCT_PALETTE)
+ {
+ unsigned index;
+ if(mode->bitdepth == 8) index = in[i];
+ else
+ {
+ size_t j = i * mode->bitdepth;
+ index = readBitsFromReversedStream(&j, in, mode->bitdepth);
+ }
+ if(index >= mode->palettesize) return 47; /*index out of palette*/
+ *r = mode->palette[index * 4 + 0];
+ *g = mode->palette[index * 4 + 1];
+ *b = mode->palette[index * 4 + 2];
+ *a = mode->palette[index * 4 + 3];
+ }
+ else if(mode->colortype == LCT_GREY_ALPHA)
+ {
+ if(mode->bitdepth == 8)
+ {
+ *r = *g = *b = in[i * 2 + 0];
+ *a = in[i * 2 + 1];
+ }
+ else
+ {
+ *r = *g = *b = in[i * 4 + 0];
+ *a = in[i * 4 + 2];
+ }
+ }
+ else if(mode->colortype == LCT_RGBA)
+ {
+ if(mode->bitdepth == 8)
+ {
+ *r = in[i * 4 + 0]; *g = in[i * 4 + 1]; *b = in[i * 4 + 2]; *a = in[i * 4 + 3];
+ }
+ else
+ {
+ *r = in[i * 8 + 0]; *g = in[i * 8 + 2]; *b = in[i * 8 + 4]; *a = in[i * 8 + 6];
+ }
+ }
+
+ return 0; /*no error*/
+}
+
+/*Get RGBA16 color of pixel with index i (y * width + x) from the raw image with
+given color type, but the given color type must be 16-bit itself.*/
+static unsigned getPixelColorRGBA16(unsigned short* r, unsigned short* g, unsigned short* b, unsigned short* a,
+ const unsigned char* in, size_t i, const LodePNGColorMode* mode)
+{
+ if(mode->bitdepth != 16) return 85; /*error: this function only supports 16-bit input*/
+
+ if(mode->colortype == LCT_GREY)
+ {
+ *r = *g = *b = 256 * in[i * 2 + 0] + in[i * 2 + 1];
+ if(mode->key_defined && 256U * in[i * 2 + 0] + in[i * 2 + 1] == mode->key_r) *a = 0;
+ else *a = 65535;
+ }
+ else if(mode->colortype == LCT_RGB)
+ {
+ *r = 256 * in[i * 6 + 0] + in[i * 6 + 1];
+ *g = 256 * in[i * 6 + 2] + in[i * 6 + 3];
+ *b = 256 * in[i * 6 + 4] + in[i * 6 + 5];
+ if(mode->key_defined && 256U * in[i * 6 + 0] + in[i * 6 + 1] == mode->key_r
+ && 256U * in[i * 6 + 2] + in[i * 6 + 3] == mode->key_g
+ && 256U * in[i * 6 + 4] + in[i * 6 + 5] == mode->key_b) *a = 0;
+ else *a = 65535;
+ }
+ else if(mode->colortype == LCT_GREY_ALPHA)
+ {
+ *r = *g = *b = 256 * in[i * 4 + 0] + in[i * 4 + 1];
+ *a = 256 * in[i * 4 + 2] + in[i * 4 + 3];
+ }
+ else if(mode->colortype == LCT_RGBA)
+ {
+ *r = 256 * in[i * 8 + 0] + in[i * 8 + 1];
+ *g = 256 * in[i * 8 + 2] + in[i * 8 + 3];
+ *b = 256 * in[i * 8 + 4] + in[i * 8 + 5];
+ *a = 256 * in[i * 8 + 6] + in[i * 8 + 7];
+ }
+ else return 85; /*error: this function only supports 16-bit input*/
+
+ return 0; /*no error*/
+}
+
+/*
+converts from any color type to 24-bit or 32-bit (later maybe more supported). return value = LodePNG error code
+the out buffer must have (w * h * bpp + 7) / 8 bytes, where bpp is the bits per pixel of the output color type
+(lodepng_get_bpp) for < 8 bpp images, there may _not_ be padding bits at the end of scanlines.
+*/
+unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
+ LodePNGColorMode* mode_out, LodePNGColorMode* mode_in,
+ unsigned w, unsigned h)
+{
+ unsigned error = 0;
+ size_t i;
+ ColorTree tree;
+
+ if(lodepng_color_mode_equal(mode_out, mode_in))
+ {
+ size_t numbytes = lodepng_get_raw_size(w, h, mode_in);
+ for(i = 0; i < numbytes; i++) out[i] = in[i];
+ return error;
+ }
+
+ if(mode_out->colortype == LCT_PALETTE)
+ {
+ size_t palsize = 1 << mode_out->bitdepth;
+ if(mode_out->palettesize < palsize) palsize = mode_out->palettesize;
+ color_tree_init(&tree, 1);
+ for(i = 0; i < palsize; i++)
+ {
+ unsigned char* p = &mode_out->palette[i * 4];
+ color_tree_add(&tree, p[0], p[1], p[2], p[3], i);
+ }
+ }
+
+ if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16)
+ {
+ size_t numpixels = w * h;
+ for(i = 0; i < numpixels; i++)
+ {
+ unsigned short r = 0, g = 0, b = 0, a = 0;
+ error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);
+ if(error) return error;
+ error = rgba16ToPixel(out, i, mode_out, r, g, b, a);
+ if(error) return error;
+ }
+ }
+ else
+ {
+ size_t numpixels = w * h;
+ for(i = 0; i < numpixels; i++)
+ {
+ unsigned char r = 0, g = 0, b = 0, a = 0;
+ error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in);
+ if(error) return error;
+ error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a);
+ if(error) return error;
+ }
+ }
+
+ if(mode_out->colortype == LCT_PALETTE)
+ {
+ color_tree_cleanup(&tree);
+ }
+
+ return error;
+}
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+typedef struct ColorProfile
+{
+ unsigned char sixteenbit; /*needs more than 8 bits per channel*/
+ unsigned char sixteenbit_done;
+
+
+ unsigned char colored; /*not greyscale*/
+ unsigned char colored_done;
+
+ unsigned char key; /*a color key is required, or more*/
+ unsigned short key_r; /*these values are always in 16-bit bitdepth in the profile*/
+ unsigned short key_g;
+ unsigned short key_b;
+ unsigned char alpha; /*alpha channel, or alpha palette, required*/
+ unsigned char alpha_done;
+
+ unsigned numcolors;
+ ColorTree tree; /*for listing the counted colors, up to 256*/
+ unsigned char* palette; /*size 1024. Remember up to the first 256 RGBA colors*/
+ unsigned maxnumcolors; /*if more than that amount counted*/
+ unsigned char numcolors_done;
+
+ unsigned greybits; /*amount of bits required for greyscale (1, 2, 4, 8). Does not take 16 bit into account.*/
+ unsigned char greybits_done;
+
+} ColorProfile;
+
+static void color_profile_init(ColorProfile* profile, LodePNGColorMode* mode)
+{
+ profile->sixteenbit = 0;
+ profile->sixteenbit_done = mode->bitdepth == 16 ? 0 : 1;
+
+ profile->colored = 0;
+ profile->colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0;
+
+ profile->key = 0;
+ profile->alpha = 0;
+ profile->alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1;
+
+ profile->numcolors = 0;
+ color_tree_init(&profile->tree, 1);
+ profile->palette = (unsigned char*)mymalloc(1024);
+ profile->maxnumcolors = 257;
+ if(lodepng_get_bpp(mode) <= 8)
+ {
+ int bpp = lodepng_get_bpp(mode);
+ profile->maxnumcolors = bpp == 1 ? 2 : (bpp == 2 ? 4 : (bpp == 4 ? 16 : 256));
+ }
+ profile->numcolors_done = 0;
+
+ profile->greybits = 1;
+ profile->greybits_done = lodepng_get_bpp(mode) == 1 ? 1 : 0;
+}
+
+static void color_profile_cleanup(ColorProfile* profile)
+{
+ color_tree_cleanup(&profile->tree);
+ myfree(profile->palette);
+}
+
+/*function used for debug purposes with C++*/
+/*void printColorProfile(ColorProfile* p)
+{
+ std::cout << "sixteenbit: " << (int)p->sixteenbit << std::endl;
+ std::cout << "sixteenbit_done: " << (int)p->sixteenbit_done << std::endl;
+ std::cout << "colored: " << (int)p->colored << std::endl;
+ std::cout << "colored_done: " << (int)p->colored_done << std::endl;
+ std::cout << "key: " << (int)p->key << std::endl;
+ std::cout << "key_r: " << (int)p->key_r << std::endl;
+ std::cout << "key_g: " << (int)p->key_g << std::endl;
+ std::cout << "key_b: " << (int)p->key_b << std::endl;
+ std::cout << "alpha: " << (int)p->alpha << std::endl;
+ std::cout << "alpha_done: " << (int)p->alpha_done << std::endl;
+ std::cout << "numcolors: " << (int)p->numcolors << std::endl;
+ std::cout << "maxnumcolors: " << (int)p->maxnumcolors << std::endl;
+ std::cout << "numcolors_done: " << (int)p->numcolors_done << std::endl;
+ std::cout << "greybits: " << (int)p->greybits << std::endl;
+ std::cout << "greybits_done: " << (int)p->greybits_done << std::endl;
+}*/
+
+/*Returns how many bits needed to represent given value (max 8 bit)*/
+unsigned getValueRequiredBits(unsigned char value)
+{
+ if(value == 0 || value == 255) return 1;
+ /*The scaling of 2-bit and 4-bit values uses multiples of 85 and 17*/
+ if(value % 17 == 0) return value % 85 == 0 ? 2 : 4;
+ return 8;
+}
+
+/*profile must already have been inited with mode.
+It's ok to set some parameters of profile to done already.*/
+static unsigned get_color_profile(ColorProfile* profile,
+ const unsigned char* in, size_t numpixels,
+ LodePNGColorMode* mode)
+{
+ unsigned error = 0;
+ size_t i;
+
+ if(mode->bitdepth == 16)
+ {
+ for(i = 0; i < numpixels; i++)
+ {
+ unsigned short r, g, b, a;
+ error = getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode);
+ if(error) break;
+
+ /*a color is considered good for 8-bit if the first byte and the second byte are equal,
+ (so if it's divisible through 257), NOT necessarily if the second byte is 0*/
+ if(!profile->sixteenbit_done
+ && (((r & 255) != ((r >> 8) & 255))
+ || ((g & 255) != ((g >> 8) & 255))
+ || ((b & 255) != ((b >> 8) & 255))))
+ {
+ profile->sixteenbit = 1;
+ profile->sixteenbit_done = 1;
+ profile->greybits_done = 1; /*greybits is not applicable anymore at 16-bit*/
+ profile->numcolors_done = 1; /*counting colors no longer useful, palette doesn't support 16-bit*/
+ }
+
+ if(!profile->colored_done && (r != g || r != b))
+ {
+ profile->colored = 1;
+ profile->colored_done = 1;
+ profile->greybits_done = 1; /*greybits is not applicable anymore*/
+ }
+
+ if(!profile->alpha_done && a != 255)
+ {
+ if(a == 0 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b)))
+ {
+ if(!profile->key)
+ {
+ profile->key = 1;
+ profile->key_r = r;
+ profile->key_g = g;
+ profile->key_b = b;
+ }
+ }
+ else
+ {
+ profile->alpha = 1;
+ profile->alpha_done = 1;
+ profile->greybits_done = 1; /*greybits is not applicable anymore*/
+ }
+ }
+
+ if(!profile->greybits_done)
+ {
+ /*assuming 8-bit r, this test does not care about 16-bit*/
+ unsigned bits = getValueRequiredBits(r);
+ if(bits > profile->greybits) profile->greybits = bits;
+ if(profile->greybits >= 8) profile->greybits_done = 1;
+ }
+
+ if(!profile->numcolors_done)
+ {
+ /*assuming 8-bit rgba, this test does not care about 16-bit*/
+ if(!color_tree_has(&profile->tree, r, g, b, a))
+ {
+ color_tree_add(&profile->tree, r, g, b, a, profile->numcolors);
+ if(profile->numcolors < 256)
+ {
+ unsigned char* p = profile->palette;
+ unsigned i = profile->numcolors;
+ p[i * 4 + 0] = r;
+ p[i * 4 + 1] = g;
+ p[i * 4 + 2] = b;
+ p[i * 4 + 3] = a;
+ }
+ profile->numcolors++;
+ if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1;
+ }
+ }
+
+ if(profile->alpha_done && profile->numcolors_done
+ && profile->colored_done && profile->sixteenbit_done && profile->greybits_done)
+ {
+ break;
+ }
+ };
+ }
+ else
+ {
+ for(i = 0; i < numpixels; i++)
+ {
+ unsigned char r, g, b, a;
+ error = getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode);
+ if(error) break;
+
+ if(!profile->colored_done && (r != g || r != b))
+ {
+ profile->colored = 1;
+ profile->colored_done = 1;
+ profile->greybits_done = 1; /*greybits is not applicable anymore*/
+ }
+
+ if(!profile->alpha_done && a != 255)
+ {
+ if(a == 0 && !(profile->key && (r != profile->key_r || g != profile->key_g || b != profile->key_b)))
+ {
+ if(!profile->key)
+ {
+ profile->key = 1;
+ profile->key_r = r;
+ profile->key_g = g;
+ profile->key_b = b;
+ }
+ }
+ else
+ {
+ profile->alpha = 1;
+ profile->alpha_done = 1;
+ profile->greybits_done = 1; /*greybits is not applicable anymore*/
+ }
+ }
+
+ if(!profile->greybits_done)
+ {
+ unsigned bits = getValueRequiredBits(r);
+ if(bits > profile->greybits) profile->greybits = bits;
+ if(profile->greybits >= 8) profile->greybits_done = 1;
+ }
+
+ if(!profile->numcolors_done)
+ {
+ if(!color_tree_has(&profile->tree, r, g, b, a))
+ {
+
+ color_tree_add(&profile->tree, r, g, b, a, profile->numcolors);
+ if(profile->numcolors < 256)
+ {
+ unsigned char* p = profile->palette;
+ unsigned i = profile->numcolors;
+ p[i * 4 + 0] = r;
+ p[i * 4 + 1] = g;
+ p[i * 4 + 2] = b;
+ p[i * 4 + 3] = a;
+ }
+ profile->numcolors++;
+ if(profile->numcolors >= profile->maxnumcolors) profile->numcolors_done = 1;
+ }
+ }
+
+ if(profile->alpha_done && profile->numcolors_done && profile->colored_done && profile->greybits_done)
+ {
+ break;
+ }
+ };
+ }
+
+ /*make the profile's key always 16-bit for consistency*/
+ if(mode->bitdepth < 16)
+ {
+ /*repeat each byte twice*/
+ profile->key_r *= 257;
+ profile->key_g *= 257;
+ profile->key_b *= 257;
+ }
+
+ return error;
+}
+
+/*updates values of mode with a potentially smaller color model. mode_out should
+contain the user chosen color model, but will be overwritten with the new chosen one.*/
+static unsigned doAutoChooseColor(LodePNGColorMode* mode_out,
+ const unsigned char* image, unsigned w, unsigned h, LodePNGColorMode* mode_in,
+ LodePNGAutoConvert auto_convert)
+{
+ ColorProfile profile;
+ unsigned error = 0;
+
+ if(auto_convert == LAC_ALPHA)
+ {
+ if(mode_out->colortype != LCT_RGBA && mode_out->colortype != LCT_GREY_ALPHA) return 0;
+ }
+
+ color_profile_init(&profile, mode_in);
+ if(auto_convert == LAC_ALPHA)
+ {
+ profile.colored_done = 1;
+ profile.greybits_done = 1;
+ profile.numcolors_done = 1;
+ profile.sixteenbit_done = 1;
+ }
+ error = get_color_profile(&profile, image, w * h, mode_in);
+
+ if(!error && auto_convert == LAC_ALPHA)
+ {
+ if(!profile.alpha)
+ {
+ mode_out->colortype = (mode_out->colortype == LCT_RGBA ? LCT_RGB : LCT_GREY);
+ }
+ }
+ else if(!error && auto_convert != LAC_ALPHA)
+ {
+ mode_out->key_defined = 0;
+
+ if(profile.sixteenbit)
+ {
+ mode_out->bitdepth = 16;
+ if(profile.alpha)
+ {
+ mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA;
+ }
+ else
+ {
+ mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY;
+ if(profile.key)
+ {
+ mode_out->key_defined = 1;
+ mode_out->key_r = profile.key_r;
+ mode_out->key_g = profile.key_g;
+ mode_out->key_b = profile.key_b;
+ }
+ }
+ }
+ else /*less than 16 bits per channel*/
+ {
+ /*don't add palette overhead if image hasn't got a lot of pixels*/
+ unsigned n = profile.numcolors;
+ int palette_ok = n <= 256 && (n * 2 < w * h);
+ unsigned palettebits = n <= 2 ? 1 : (n <= 4 ? 2 : (n <= 16 ? 4 : 8));
+ int grey_ok = !profile.colored && !profile.alpha; /*grey without alpha, with potentially low bits*/
+ if(palette_ok || grey_ok)
+ {
+ if(!palette_ok || (grey_ok && profile.greybits <= palettebits))
+ {
+ mode_out->colortype = LCT_GREY;
+ mode_out->bitdepth = profile.greybits;
+ if(profile.key)
+ {
+ unsigned keyval = profile.key_r;
+ keyval &= (profile.greybits - 1); /*same subgroup of bits repeated, so taking right bits is fine*/
+ mode_out->key_defined = 1;
+ mode_out->key_r = keyval;
+ mode_out->key_g = keyval;
+ mode_out->key_b = keyval;
+ }
+ }
+ else
+ {
+ /*fill in the palette*/
+ unsigned i;
+ unsigned char* p = profile.palette;
+ for(i = 0; i < profile.numcolors; i++)
+ {
+ error = lodepng_palette_add(mode_out, p[i * 4 + 0], p[i * 4 + 1], p[i * 4 + 2], p[i * 4 + 3]);
+ if(error) break;
+ }
+
+ mode_out->colortype = LCT_PALETTE;
+ mode_out->bitdepth = palettebits;
+ }
+ }
+ else /*8-bit per channel*/
+ {
+ mode_out->bitdepth = 8;
+ if(profile.alpha)
+ {
+ mode_out->colortype = profile.colored ? LCT_RGBA : LCT_GREY_ALPHA;
+ }
+ else
+ {
+ mode_out->colortype = profile.colored ? LCT_RGB : LCT_GREY /*LCT_GREY normally won't occur, already done earlier*/;
+ if(profile.key)
+ {
+ mode_out->key_defined = 1;
+ mode_out->key_r = profile.key_r % 256;
+ mode_out->key_g = profile.key_g % 256;
+ mode_out->key_b = profile.key_b % 256;
+ }
+ }
+ }
+ }
+ }
+
+ color_profile_cleanup(&profile);
+
+ if(mode_out->colortype == LCT_PALETTE && mode_in->palettesize == mode_out->palettesize)
+ {
+ /*In this case keep the palette order of the input, so that the user can choose an optimal one*/
+ size_t i;
+ for(i = 0; i < mode_in->palettesize * 4; i++)
+ {
+ mode_out->palette[i] = mode_in->palette[i];
+ }
+ }
+
+ if(auto_convert == LAC_AUTO_NO_NIBBLES && mode_out->bitdepth < 8)
+ {
+ /*palette can keep its small amount of colors, as long as no indices use it*/
+ mode_out->bitdepth = 8;
+ }
+
+ return error;
+}
+
+#endif /* #ifdef LODEPNG_COMPILE_ENCODER */
+
+/*
+Paeth predicter, used by PNG filter type 4
+The parameters are of type short, but should come from unsigned chars, the shorts
+are only needed to make the paeth calculation correct.
+*/
+static unsigned char paethPredictor(short a, short b, short c)
+{
+ short pa = abs(b - c);
+ short pb = abs(a - c);
+ short pc = abs(a + b - c - c);
+
+ if(pc < pa && pc < pb) return (unsigned char)c;
+ else if(pb < pa) return (unsigned char)b;
+ else return (unsigned char)a;
+}
+
+/*shared values used by multiple Adam7 related functions*/
+
+static const unsigned ADAM7_IX[7] = { 0, 4, 0, 2, 0, 1, 0 }; /*x start values*/
+static const unsigned ADAM7_IY[7] = { 0, 0, 4, 0, 2, 0, 1 }; /*y start values*/
+static const unsigned ADAM7_DX[7] = { 8, 8, 4, 4, 2, 2, 1 }; /*x delta values*/
+static const unsigned ADAM7_DY[7] = { 8, 8, 8, 4, 4, 2, 2 }; /*y delta values*/
+
+static void Adam7_getpassvalues(unsigned passw[7], unsigned passh[7], size_t filter_passstart[8],
+ size_t padded_passstart[8], size_t passstart[8], unsigned w, unsigned h, unsigned bpp)
+{
+ /*the passstart values have 8 values: the 8th one indicates the byte after the end of the 7th (= last) pass*/
+ unsigned i;
+
+ /*calculate width and height in pixels of each pass*/
+ for(i = 0; i < 7; i++)
+ {
+ passw[i] = (w + ADAM7_DX[i] - ADAM7_IX[i] - 1) / ADAM7_DX[i];
+ passh[i] = (h + ADAM7_DY[i] - ADAM7_IY[i] - 1) / ADAM7_DY[i];
+ if(passw[i] == 0) passh[i] = 0;
+ if(passh[i] == 0) passw[i] = 0;
+ }
+
+ filter_passstart[0] = padded_passstart[0] = passstart[0] = 0;
+ for(i = 0; i < 7; i++)
+ {
+ /*if passw[i] is 0, it's 0 bytes, not 1 (no filtertype-byte)*/
+ filter_passstart[i + 1] = filter_passstart[i]
+ + ((passw[i] && passh[i]) ? passh[i] * (1 + (passw[i] * bpp + 7) / 8) : 0);
+ /*bits padded if needed to fill full byte at end of each scanline*/
+ padded_passstart[i + 1] = padded_passstart[i] + passh[i] * ((passw[i] * bpp + 7) / 8);
+ /*only padded at end of reduced image*/
+ passstart[i + 1] = passstart[i] + (passh[i] * passw[i] * bpp + 7) / 8;
+ }
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / PNG Decoder / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*read the information from the header and store it in the LodePNGInfo. return value is error*/
+unsigned lodepng_inspect(unsigned* w, unsigned* h, LodePNGState* state,
+ const unsigned char* in, size_t insize)
+{
+ LodePNGInfo* info = &state->info_png;
+ if(insize == 0 || in == 0)
+ {
+ CERROR_RETURN_ERROR(state->error, 48); /*error: the given data is empty*/
+ }
+ if(insize < 29)
+ {
+ CERROR_RETURN_ERROR(state->error, 27); /*error: the data length is smaller than the length of a PNG header*/
+ }
+
+ /*when decoding a new PNG image, make sure all parameters created after previous decoding are reset*/
+ lodepng_info_cleanup(info);
+ lodepng_info_init(info);
+
+ if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71
+ || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10)
+ {
+ CERROR_RETURN_ERROR(state->error, 28); /*error: the first 8 bytes are not the correct PNG signature*/
+ }
+ if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R')
+ {
+ CERROR_RETURN_ERROR(state->error, 29); /*error: it doesn't start with a IHDR chunk!*/
+ }
+
+ /*read the values given in the header*/
+ *w = lodepng_read32bitInt(&in[16]);
+ *h = lodepng_read32bitInt(&in[20]);
+ info->color.bitdepth = in[24];
+ info->color.colortype = (LodePNGColorType)in[25];
+ info->compression_method = in[26];
+ info->filter_method = in[27];
+ info->interlace_method = in[28];
+
+ if(!state->decoder.ignore_crc)
+ {
+ unsigned CRC = lodepng_read32bitInt(&in[29]);
+ unsigned checksum = lodepng_crc32(&in[12], 17);
+ if(CRC != checksum)
+ {
+ CERROR_RETURN_ERROR(state->error, 57); /*invalid CRC*/
+ }
+ }
+
+ /*error: only compression method 0 is allowed in the specification*/
+ if(info->compression_method != 0) CERROR_RETURN_ERROR(state->error, 32);
+ /*error: only filter method 0 is allowed in the specification*/
+ if(info->filter_method != 0) CERROR_RETURN_ERROR(state->error, 33);
+ /*error: only interlace methods 0 and 1 exist in the specification*/
+ if(info->interlace_method > 1) CERROR_RETURN_ERROR(state->error, 34);
+
+ state->error = checkColorValidity(info->color.colortype, info->color.bitdepth);
+ return state->error;
+}
+
+static unsigned unfilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon,
+ size_t bytewidth, unsigned char filterType, size_t length)
+{
+ /*
+ For PNG filter method 0
+ unfilter a PNG image scanline by scanline. when the pixels are smaller than 1 byte,
+ the filter works byte per byte (bytewidth = 1)
+ precon is the previous unfiltered scanline, recon the result, scanline the current one
+ the incoming scanlines do NOT include the filtertype byte, that one is given in the parameter filterType instead
+ recon and scanline MAY be the same memory address! precon must be disjoint.
+ */
+
+ size_t i;
+ switch(filterType)
+ {
+ case 0:
+ for(i = 0; i < length; i++) recon[i] = scanline[i];
+ break;
+ case 1:
+ for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
+ for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth];
+ break;
+ case 2:
+ if(precon)
+ {
+ for(i = 0; i < length; i++) recon[i] = scanline[i] + precon[i];
+ }
+ else
+ {
+ for(i = 0; i < length; i++) recon[i] = scanline[i];
+ }
+ break;
+ case 3:
+ if(precon)
+ {
+ for(i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2;
+ for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
+ }
+ else
+ {
+ for(i = 0; i < bytewidth; i++) recon[i] = scanline[i];
+ for(i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2;
+ }
+ break;
+ case 4:
+ if(precon)
+ {
+ for(i = 0; i < bytewidth; i++)
+ {
+ recon[i] = (scanline[i] + precon[i]); /*paethPredictor(0, precon[i], 0) is always precon[i]*/
+ }
+ for(i = bytewidth; i < length; i++)
+ {
+ recon[i] = (scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]));
+ }
+ }
+ else
+ {
+ for(i = 0; i < bytewidth; i++)
+ {
+ recon[i] = scanline[i];
+ }
+ for(i = bytewidth; i < length; i++)
+ {
+ /*paethPredictor(recon[i - bytewidth], 0, 0) is always recon[i - bytewidth]*/
+ recon[i] = (scanline[i] + recon[i - bytewidth]);
+ }
+ }
+ break;
+ default: return 36; /*error: unexisting filter type given*/
+ }
+ return 0;
+}
+
+static unsigned unfilter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
+{
+ /*
+ For PNG filter method 0
+ this function unfilters a single image (e.g. without interlacing this is called once, with Adam7 seven times)
+ out must have enough bytes allocated already, in must have the scanlines + 1 filtertype byte per scanline
+ w and h are image dimensions or dimensions of reduced image, bpp is bits per pixel
+ in and out are allowed to be the same memory address (but aren't the same size since in has the extra filter bytes)
+ */
+
+ unsigned y;
+ unsigned char* prevline = 0;
+
+ /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
+ size_t bytewidth = (bpp + 7) / 8;
+ size_t linebytes = (w * bpp + 7) / 8;
+
+ for(y = 0; y < h; y++)
+ {
+ size_t outindex = linebytes * y;
+ size_t inindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
+ unsigned char filterType = in[inindex];
+
+ CERROR_TRY_RETURN(unfilterScanline(&out[outindex], &in[inindex + 1], prevline, bytewidth, filterType, linebytes));
+
+ prevline = &out[outindex];
+ }
+
+ return 0;
+}
+
+static void Adam7_deinterlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
+{
+ /*Note: this function works on image buffers WITHOUT padding bits at end of scanlines
+ with non-multiple-of-8 bit amounts, only between reduced images is padding
+ out must be big enough AND must be 0 everywhere if bpp < 8 in the current implementation
+ (because that's likely a little bit faster)*/
+ unsigned passw[7], passh[7];
+ size_t filter_passstart[8], padded_passstart[8], passstart[8];
+ unsigned i;
+
+ Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+ if(bpp >= 8)
+ {
+ for(i = 0; i < 7; i++)
+ {
+ unsigned x, y, b;
+ size_t bytewidth = bpp / 8;
+ for(y = 0; y < passh[i]; y++)
+ for(x = 0; x < passw[i]; x++)
+ {
+ size_t pixelinstart = passstart[i] + (y * passw[i] + x) * bytewidth;
+ size_t pixeloutstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
+ for(b = 0; b < bytewidth; b++)
+ {
+ out[pixeloutstart + b] = in[pixelinstart + b];
+ }
+ }
+ }
+ }
+ else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
+ {
+ for(i = 0; i < 7; i++)
+ {
+ unsigned x, y, b;
+ unsigned ilinebits = bpp * passw[i];
+ unsigned olinebits = bpp * w;
+ size_t obp, ibp; /*bit pointers (for out and in buffer)*/
+ for(y = 0; y < passh[i]; y++)
+ for(x = 0; x < passw[i]; x++)
+ {
+ ibp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
+ obp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
+ for(b = 0; b < bpp; b++)
+ {
+ unsigned char bit = readBitFromReversedStream(&ibp, in);
+ /*note that this function assumes the out buffer is completely 0, use setBitOfReversedStream otherwise*/
+ setBitOfReversedStream0(&obp, out, bit);
+ }
+ }
+ }
+ }
+}
+
+static void removePaddingBits(unsigned char* out, const unsigned char* in,
+ size_t olinebits, size_t ilinebits, unsigned h)
+{
+ /*
+ After filtering there are still padding bits if scanlines have non multiple of 8 bit amounts. They need
+ to be removed (except at last scanline of (Adam7-reduced) image) before working with pure image buffers
+ for the Adam7 code, the color convert code and the output to the user.
+ in and out are allowed to be the same buffer, in may also be higher but still overlapping; in must
+ have >= ilinebits*h bits, out must have >= olinebits*h bits, olinebits must be <= ilinebits
+ also used to move bits after earlier such operations happened, e.g. in a sequence of reduced images from Adam7
+ only useful if (ilinebits - olinebits) is a value in the range 1..7
+ */
+ unsigned y;
+ size_t diff = ilinebits - olinebits;
+ size_t ibp = 0, obp = 0; /*input and output bit pointers*/
+ for(y = 0; y < h; y++)
+ {
+ size_t x;
+ for(x = 0; x < olinebits; x++)
+ {
+ unsigned char bit = readBitFromReversedStream(&ibp, in);
+ setBitOfReversedStream(&obp, out, bit);
+ }
+ ibp += diff;
+ }
+}
+
+/*out must be buffer big enough to contain full image, and in must contain the full decompressed data from
+the IDAT chunks (with filter index bytes and possible padding bits)
+return value is error*/
+static unsigned postProcessScanlines(unsigned char* out, unsigned char* in,
+ unsigned w, unsigned h, const LodePNGInfo* info_png)
+{
+ /*
+ This function converts the filtered-padded-interlaced data into pure 2D image buffer with the PNG's colortype.
+ Steps:
+ *) if no Adam7: 1) unfilter 2) remove padding bits (= posible extra bits per scanline if bpp < 8)
+ *) if adam7: 1) 7x unfilter 2) 7x remove padding bits 3) Adam7_deinterlace
+ NOTE: the in buffer will be overwritten with intermediate data!
+ */
+ unsigned bpp = lodepng_get_bpp(&info_png->color);
+ if(bpp == 0) return 31; /*error: invalid colortype*/
+
+ if(info_png->interlace_method == 0)
+ {
+ if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
+ {
+ CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp));
+ removePaddingBits(out, in, w * bpp, ((w * bpp + 7) / 8) * 8, h);
+ }
+ /*we can immediatly filter into the out buffer, no other steps needed*/
+ else CERROR_TRY_RETURN(unfilter(out, in, w, h, bpp));
+ }
+ else /*interlace_method is 1 (Adam7)*/
+ {
+ unsigned passw[7], passh[7]; size_t filter_passstart[8], padded_passstart[8], passstart[8];
+ unsigned i;
+
+ Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+ for(i = 0; i < 7; i++)
+ {
+ CERROR_TRY_RETURN(unfilter(&in[padded_passstart[i]], &in[filter_passstart[i]], passw[i], passh[i], bpp));
+ /*TODO: possible efficiency improvement: if in this reduced image the bits fit nicely in 1 scanline,
+ move bytes instead of bits or move not at all*/
+ if(bpp < 8)
+ {
+ /*remove padding bits in scanlines; after this there still may be padding
+ bits between the different reduced images: each reduced image still starts nicely at a byte*/
+ removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], passw[i] * bpp,
+ ((passw[i] * bpp + 7) / 8) * 8, passh[i]);
+ }
+ }
+
+ Adam7_deinterlace(out, in, w, h, bpp);
+ }
+
+ return 0;
+}
+
+/*read a PNG, the result will be in the same color type as the PNG (hence "generic")*/
+static void decodeGeneric(unsigned char** out, unsigned* w, unsigned* h,
+ LodePNGState* state,
+ const unsigned char* in, size_t insize)
+{
+ unsigned char IEND = 0;
+ const unsigned char* chunk;
+ size_t i;
+ ucvector idat; /*the data from idat chunks*/
+
+ /*for unknown chunk order*/
+ unsigned unknown = 0;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ unsigned critical_pos = 1; /*1 = after IHDR, 2 = after PLTE, 3 = after IDAT*/
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+ /*provide some proper output values if error will happen*/
+ *out = 0;
+
+ state->error = lodepng_inspect(w, h, state, in, insize); /*reads header and resets other parameters in state->info_png*/
+ if(state->error) return;
+
+ ucvector_init(&idat);
+ chunk = &in[33]; /*first byte of the first chunk after the header*/
+
+ /*loop through the chunks, ignoring unknown chunks and stopping at IEND chunk.
+ IDAT data is put at the start of the in buffer*/
+ while(!IEND && !state->error)
+ {
+ unsigned chunkLength;
+ const unsigned char* data; /*the data in the chunk*/
+
+ /*error: size of the in buffer too small to contain next chunk*/
+ if((size_t)((chunk - in) + 12) > insize || chunk < in) CERROR_BREAK(state->error, 30);
+
+ /*length of the data of the chunk, excluding the length bytes, chunk type and CRC bytes*/
+ chunkLength = lodepng_chunk_length(chunk);
+ /*error: chunk length larger than the max PNG chunk size*/
+ if(chunkLength > 2147483647) CERROR_BREAK(state->error, 63);
+
+ if((size_t)((chunk - in) + chunkLength + 12) > insize || (chunk + chunkLength + 12) < in)
+ {
+ CERROR_BREAK(state->error, 64); /*error: size of the in buffer too small to contain next chunk*/
+ }
+
+ data = lodepng_chunk_data_const(chunk);
+
+ /*IDAT chunk, containing compressed image data*/
+ if(lodepng_chunk_type_equals(chunk, "IDAT"))
+ {
+ size_t oldsize = idat.size;
+ if(!ucvector_resize(&idat, oldsize + chunkLength)) CERROR_BREAK(state->error, 83 /*alloc fail*/);
+ for(i = 0; i < chunkLength; i++) idat.data[oldsize + i] = data[i];
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ critical_pos = 3;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ }
+ /*IEND chunk*/
+ else if(lodepng_chunk_type_equals(chunk, "IEND"))
+ {
+ IEND = 1;
+ }
+ /*palette chunk (PLTE)*/
+ else if(lodepng_chunk_type_equals(chunk, "PLTE"))
+ {
+ unsigned pos = 0;
+ if(state->info_png.color.palette) myfree(state->info_png.color.palette);
+ state->info_png.color.palettesize = chunkLength / 3;
+ state->info_png.color.palette = (unsigned char*)mymalloc(4 * state->info_png.color.palettesize);
+ if(!state->info_png.color.palette && state->info_png.color.palettesize)
+ {
+ state->info_png.color.palettesize = 0;
+ CERROR_BREAK(state->error, 83); /*alloc fail*/
+ }
+ if(state->info_png.color.palettesize > 256) CERROR_BREAK(state->error, 38); /*error: palette too big*/
+
+ for(i = 0; i < state->info_png.color.palettesize; i++)
+ {
+ state->info_png.color.palette[4 * i + 0] = data[pos++]; /*R*/
+ state->info_png.color.palette[4 * i + 1] = data[pos++]; /*G*/
+ state->info_png.color.palette[4 * i + 2] = data[pos++]; /*B*/
+ state->info_png.color.palette[4 * i + 3] = 255; /*alpha*/
+ }
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ critical_pos = 2;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ }
+ /*palette transparency chunk (tRNS)*/
+ else if(lodepng_chunk_type_equals(chunk, "tRNS"))
+ {
+ if(state->info_png.color.colortype == LCT_PALETTE)
+ {
+ /*error: more alpha values given than there are palette entries*/
+ if(chunkLength > state->info_png.color.palettesize) CERROR_BREAK(state->error, 38);
+
+ for(i = 0; i < chunkLength; i++) state->info_png.color.palette[4 * i + 3] = data[i];
+ }
+ else if(state->info_png.color.colortype == LCT_GREY)
+ {
+ /*error: this chunk must be 2 bytes for greyscale image*/
+ if(chunkLength != 2) CERROR_BREAK(state->error, 30);
+
+ state->info_png.color.key_defined = 1;
+ state->info_png.color.key_r = state->info_png.color.key_g
+ = state->info_png.color.key_b = 256 * data[0] + data[1];
+ }
+ else if(state->info_png.color.colortype == LCT_RGB)
+ {
+ /*error: this chunk must be 6 bytes for RGB image*/
+ if(chunkLength != 6) CERROR_BREAK(state->error, 41);
+
+ state->info_png.color.key_defined = 1;
+ state->info_png.color.key_r = 256 * data[0] + data[1];
+ state->info_png.color.key_g = 256 * data[2] + data[3];
+ state->info_png.color.key_b = 256 * data[4] + data[5];
+ }
+ else CERROR_BREAK(state->error, 42); /*error: tRNS chunk not allowed for other color models*/
+ }
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ /*background color chunk (bKGD)*/
+ else if(lodepng_chunk_type_equals(chunk, "bKGD"))
+ {
+ if(state->info_png.color.colortype == LCT_PALETTE)
+ {
+ /*error: this chunk must be 1 byte for indexed color image*/
+ if(chunkLength != 1) CERROR_BREAK(state->error, 43);
+
+ state->info_png.background_defined = 1;
+ state->info_png.background_r = state->info_png.background_g = state->info_png.background_b = data[0];
+ }
+ else if(state->info_png.color.colortype == LCT_GREY || state->info_png.color.colortype == LCT_GREY_ALPHA)
+ {
+ /*error: this chunk must be 2 bytes for greyscale image*/
+ if(chunkLength != 2) CERROR_BREAK(state->error, 44);
+
+ state->info_png.background_defined = 1;
+ state->info_png.background_r = state->info_png.background_g = state->info_png.background_b
+ = 256 * data[0] + data[1];
+ }
+ else if(state->info_png.color.colortype == LCT_RGB || state->info_png.color.colortype == LCT_RGBA)
+ {
+ /*error: this chunk must be 6 bytes for greyscale image*/
+ if(chunkLength != 6) CERROR_BREAK(state->error, 45);
+
+ state->info_png.background_defined = 1;
+ state->info_png.background_r = 256 * data[0] + data[1];
+ state->info_png.background_g = 256 * data[2] + data[3];
+ state->info_png.background_b = 256 * data[4] + data[5];
+ }
+ }
+ /*text chunk (tEXt)*/
+ else if(lodepng_chunk_type_equals(chunk, "tEXt"))
+ {
+ if(state->decoder.read_text_chunks)
+ {
+ char *key = 0, *str = 0;
+
+ while(!state->error) /*not really a while loop, only used to break on error*/
+ {
+ unsigned length, string2_begin;
+
+ length = 0;
+ while(length < chunkLength && data[length] != 0) length++;
+ /*error, end reached, no null terminator?*/
+ if(length + 1 >= chunkLength) CERROR_BREAK(state->error, 75);
+
+ key = (char*)mymalloc(length + 1);
+ if(!key) CERROR_BREAK(state->error, 83); /*alloc fail*/
+
+ key[length] = 0;
+ for(i = 0; i < length; i++) key[i] = data[i];
+
+ string2_begin = length + 1;
+ /*error, end reached, no null terminator?*/
+ if(string2_begin > chunkLength) CERROR_BREAK(state->error, 75);
+
+ length = chunkLength - string2_begin;
+ str = (char*)mymalloc(length + 1);
+ if(!str) CERROR_BREAK(state->error, 83); /*alloc fail*/
+
+ str[length] = 0;
+ for(i = 0; i < length; i++) str[i] = data[string2_begin + i];
+
+ state->error = lodepng_add_text(&state->info_png, key, str);
+
+ break;
+ }
+
+ myfree(key);
+ myfree(str);
+ }
+ }
+ /*compressed text chunk (zTXt)*/
+ else if(lodepng_chunk_type_equals(chunk, "zTXt"))
+ {
+ if(state->decoder.read_text_chunks)
+ {
+ unsigned length, string2_begin;
+ char *key = 0;
+ ucvector decoded;
+
+ ucvector_init(&decoded);
+
+ while(!state->error) /*not really a while loop, only used to break on error*/
+ {
+ for(length = 0; length < chunkLength && data[length] != 0; length++) ;
+ if(length + 2 >= chunkLength) CERROR_BREAK(state->error, 75); /*no null termination, corrupt?*/
+
+ key = (char*)mymalloc(length + 1);
+ if(!key) CERROR_BREAK(state->error, 83); /*alloc fail*/
+
+ key[length] = 0;
+ for(i = 0; i < length; i++) key[i] = data[i];
+
+ if(data[length + 1] != 0) CERROR_BREAK(state->error, 72); /*the 0 byte indicating compression must be 0*/
+
+ string2_begin = length + 2;
+ if(string2_begin > chunkLength) CERROR_BREAK(state->error, 75); /*no null termination, corrupt?*/
+
+ length = chunkLength - string2_begin;
+ state->error = lodepng_zlib_decompress(&decoded.data, &decoded.size,
+ (unsigned char*)(&data[string2_begin]),
+ length, &state->decoder.zlibsettings);
+ if(state->error) break;
+ ucvector_push_back(&decoded, 0);
+
+ state->error = lodepng_add_text(&state->info_png, key, (char*)decoded.data);
+
+ break;
+ }
+
+ myfree(key);
+ ucvector_cleanup(&decoded);
+ if(state->error) break;
+ }
+ }
+ /*international text chunk (iTXt)*/
+ else if(lodepng_chunk_type_equals(chunk, "iTXt"))
+ {
+ if(state->decoder.read_text_chunks)
+ {
+ unsigned length, begin, compressed;
+ char *key = 0, *langtag = 0, *transkey = 0;
+ ucvector decoded;
+ ucvector_init(&decoded);
+
+ while(!state->error) /*not really a while loop, only used to break on error*/
+ {
+ /*Quick check if the chunk length isn't too small. Even without check
+ it'd still fail with other error checks below if it's too short. This just gives a different error code.*/
+ if(chunkLength < 5) CERROR_BREAK(state->error, 30); /*iTXt chunk too short*/
+
+ /*read the key*/
+ for(length = 0; length < chunkLength && data[length] != 0; length++) ;
+ if(length + 2 >= chunkLength) CERROR_BREAK(state->error, 75); /*no null termination char found*/
+
+ key = (char*)mymalloc(length + 1);
+ if(!key) CERROR_BREAK(state->error, 83); /*alloc fail*/
+
+ key[length] = 0;
+ for(i = 0; i < length; i++) key[i] = data[i];
+
+ /*read the compression method*/
+ compressed = data[length + 1];
+ if(data[length + 2] != 0) CERROR_BREAK(state->error, 72); /*the 0 byte indicating compression must be 0*/
+
+ /*read the langtag*/
+ begin = length + 3;
+ length = 0;
+ for(i = begin; i < chunkLength && data[i] != 0; i++) length++;
+ if(begin + length + 1 >= chunkLength) CERROR_BREAK(state->error, 75); /*no null termination char found*/
+
+ langtag = (char*)mymalloc(length + 1);
+ if(!langtag) CERROR_BREAK(state->error, 83); /*alloc fail*/
+
+ langtag[length] = 0;
+ for(i = 0; i < length; i++) langtag[i] = data[begin + i];
+
+ /*read the transkey*/
+ begin += length + 1;
+ length = 0;
+ for(i = begin; i < chunkLength && data[i] != 0; i++) length++;
+ if(begin + length + 1 >= chunkLength) CERROR_BREAK(state->error, 75); /*no null termination, corrupt?*/
+
+ transkey = (char*)mymalloc(length + 1);
+ if(!transkey) CERROR_BREAK(state->error, 83); /*alloc fail*/
+
+ transkey[length] = 0;
+ for(i = 0; i < length; i++) transkey[i] = data[begin + i];
+
+ /*read the actual text*/
+ begin += length + 1;
+ if(begin > chunkLength) CERROR_BREAK(state->error, 75); /*no null termination, corrupt?*/
+
+ length = chunkLength - begin;
+
+ if(compressed)
+ {
+ state->error = lodepng_zlib_decompress(&decoded.data, &decoded.size,
+ (unsigned char*)(&data[begin]),
+ length, &state->decoder.zlibsettings);
+ if(state->error) break;
+ if(decoded.allocsize < decoded.size) decoded.allocsize = decoded.size;
+ ucvector_push_back(&decoded, 0);
+ }
+ else
+ {
+ if(!ucvector_resize(&decoded, length + 1)) CERROR_BREAK(state->error, 83 /*alloc fail*/);
+
+ decoded.data[length] = 0;
+ for(i = 0; i < length; i++) decoded.data[i] = data[begin + i];
+ }
+
+ state->error = lodepng_add_itext(&state->info_png, key, langtag, transkey, (char*)decoded.data);
+
+ break;
+ }
+
+ myfree(key);
+ myfree(langtag);
+ myfree(transkey);
+ ucvector_cleanup(&decoded);
+ if(state->error) break;
+ }
+ }
+ else if(lodepng_chunk_type_equals(chunk, "tIME"))
+ {
+ if(chunkLength != 7) CERROR_BREAK(state->error, 73); /*invalid tIME chunk size*/
+
+ state->info_png.time_defined = 1;
+ state->info_png.time.year = 256 * data[0] + data[+ 1];
+ state->info_png.time.month = data[2];
+ state->info_png.time.day = data[3];
+ state->info_png.time.hour = data[4];
+ state->info_png.time.minute = data[5];
+ state->info_png.time.second = data[6];
+ }
+ else if(lodepng_chunk_type_equals(chunk, "pHYs"))
+ {
+ if(chunkLength != 9) CERROR_BREAK(state->error, 74); /*invalid pHYs chunk size*/
+
+ state->info_png.phys_defined = 1;
+ state->info_png.phys_x = 16777216 * data[0] + 65536 * data[1] + 256 * data[2] + data[3];
+ state->info_png.phys_y = 16777216 * data[4] + 65536 * data[5] + 256 * data[6] + data[7];
+ state->info_png.phys_unit = data[8];
+ }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ else /*it's not an implemented chunk type, so ignore it: skip over the data*/
+ {
+ /*error: unknown critical chunk (5th bit of first byte of chunk type is 0)*/
+ if(!lodepng_chunk_ancillary(chunk)) CERROR_BREAK(state->error, 69);
+
+ unknown = 1;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ if(state->decoder.remember_unknown_chunks)
+ {
+ state->error = lodepng_chunk_append(&state->info_png.unknown_chunks_data[critical_pos - 1],
+ &state->info_png.unknown_chunks_size[critical_pos - 1], chunk);
+ if(state->error) break;
+ }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ }
+
+ if(!state->decoder.ignore_crc && !unknown) /*check CRC if wanted, only on known chunk types*/
+ {
+ if(lodepng_chunk_check_crc(chunk)) CERROR_BREAK(state->error, 57); /*invalid CRC*/
+ }
+
+ if(!IEND) chunk = lodepng_chunk_next_const(chunk);
+ }
+
+ if(!state->error)
+ {
+ ucvector scanlines;
+ ucvector_init(&scanlines);
+
+ /*maximum final image length is already reserved in the vector's length - this is not really necessary*/
+ if(!ucvector_resize(&scanlines, lodepng_get_raw_size(*w, *h, &state->info_png.color) + *h))
+ {
+ state->error = 83; /*alloc fail*/
+ }
+ if(!state->error)
+ {
+ /*decompress with the Zlib decompressor*/
+ state->error = lodepng_zlib_decompress(&scanlines.data, &scanlines.size, idat.data,
+ idat.size, &state->decoder.zlibsettings);
+ }
+
+ if(!state->error)
+ {
+ ucvector outv;
+ ucvector_init(&outv);
+ if(!ucvector_resizev(&outv,
+ lodepng_get_raw_size(*w, *h, &state->info_png.color), 0)) state->error = 83; /*alloc fail*/
+ if(!state->error) state->error = postProcessScanlines(outv.data, scanlines.data, *w, *h, &state->info_png);
+ *out = outv.data;
+ }
+ ucvector_cleanup(&scanlines);
+ }
+
+ ucvector_cleanup(&idat);
+}
+
+unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,
+ LodePNGState* state,
+ const unsigned char* in, size_t insize)
+{
+ *out = 0;
+ decodeGeneric(out, w, h, state, in, insize);
+ if(state->error) return state->error;
+ if(!state->decoder.color_convert || lodepng_color_mode_equal(&state->info_raw, &state->info_png.color))
+ {
+ /*same color type, no copying or converting of data needed*/
+ /*store the info_png color settings on the info_raw so that the info_raw still reflects what colortype
+ the raw image has to the end user*/
+ if(!state->decoder.color_convert)
+ {
+ state->error = lodepng_color_mode_copy(&state->info_raw, &state->info_png.color);
+ if(state->error) return state->error;
+ }
+ }
+ else
+ {
+ /*color conversion needed; sort of copy of the data*/
+ unsigned char* data = *out;
+ size_t outsize;
+
+ /*TODO: check if this works according to the statement in the documentation: "The converter can convert
+ from greyscale input color type, to 8-bit greyscale or greyscale with alpha"*/
+ if(!(state->info_raw.colortype == LCT_RGB || state->info_raw.colortype == LCT_RGBA)
+ && !(state->info_raw.bitdepth == 8))
+ {
+ return 56; /*unsupported color mode conversion*/
+ }
+
+ outsize = lodepng_get_raw_size(*w, *h, &state->info_raw);
+ *out = (unsigned char*)mymalloc(outsize);
+ if(!(*out))
+ {
+ state->error = 83; /*alloc fail*/
+ }
+ else state->error = lodepng_convert(*out, data, &state->info_raw, &state->info_png.color, *w, *h);
+ myfree(data);
+ }
+ return state->error;
+}
+
+unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in,
+ size_t insize, LodePNGColorType colortype, unsigned bitdepth)
+{
+ unsigned error;
+ LodePNGState state;
+ lodepng_state_init(&state);
+ state.info_raw.colortype = colortype;
+ state.info_raw.bitdepth = bitdepth;
+ error = lodepng_decode(out, w, h, &state, in, insize);
+ lodepng_state_cleanup(&state);
+ return error;
+}
+
+unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
+{
+ return lodepng_decode_memory(out, w, h, in, insize, LCT_RGBA, 8);
+}
+
+unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h, const unsigned char* in, size_t insize)
+{
+ return lodepng_decode_memory(out, w, h, in, insize, LCT_RGB, 8);
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename,
+ LodePNGColorType colortype, unsigned bitdepth)
+{
+ unsigned char* buffer;
+ size_t buffersize;
+ unsigned error;
+ error = lodepng_load_file(&buffer, &buffersize, filename);
+ if(!error) error = lodepng_decode_memory(out, w, h, buffer, buffersize, colortype, bitdepth);
+ myfree(buffer);
+ return error;
+}
+
+unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename)
+{
+ return lodepng_decode_file(out, w, h, filename, LCT_RGBA, 8);
+}
+
+unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h, const char* filename)
+{
+ return lodepng_decode_file(out, w, h, filename, LCT_RGB, 8);
+}
+#endif /*LODEPNG_COMPILE_DISK*/
+
+void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings)
+{
+ settings->color_convert = 1;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ settings->read_text_chunks = 1;
+ settings->remember_unknown_chunks = 0;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ settings->ignore_crc = 0;
+ lodepng_decompress_settings_init(&settings->zlibsettings);
+}
+
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)
+
+void lodepng_state_init(LodePNGState* state)
+{
+#ifdef LODEPNG_COMPILE_DECODER
+ lodepng_decoder_settings_init(&state->decoder);
+#endif /*LODEPNG_COMPILE_DECODER*/
+#ifdef LODEPNG_COMPILE_ENCODER
+ lodepng_encoder_settings_init(&state->encoder);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+ lodepng_color_mode_init(&state->info_raw);
+ lodepng_info_init(&state->info_png);
+ state->error = 1;
+}
+
+void lodepng_state_cleanup(LodePNGState* state)
+{
+ lodepng_color_mode_cleanup(&state->info_raw);
+ lodepng_info_cleanup(&state->info_png);
+}
+
+void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source)
+{
+ lodepng_state_cleanup(dest);
+ *dest = *source;
+ lodepng_color_mode_init(&dest->info_raw);
+ lodepng_info_init(&dest->info_png);
+ dest->error = lodepng_color_mode_copy(&dest->info_raw, &source->info_raw); if(dest->error) return;
+ dest->error = lodepng_info_copy(&dest->info_png, &source->info_png); if(dest->error) return;
+}
+
+#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */
+
+#ifdef LODEPNG_COMPILE_ENCODER
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* / PNG Encoder / */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+/*chunkName must be string of 4 characters*/
+static unsigned addChunk(ucvector* out, const char* chunkName, const unsigned char* data, size_t length)
+{
+ CERROR_TRY_RETURN(lodepng_chunk_create(&out->data, &out->size, (unsigned)length, chunkName, data));
+ out->allocsize = out->size; /*fix the allocsize again*/
+ return 0;
+}
+
+static void writeSignature(ucvector* out)
+{
+ /*8 bytes PNG signature, aka the magic bytes*/
+ ucvector_push_back(out, 137);
+ ucvector_push_back(out, 80);
+ ucvector_push_back(out, 78);
+ ucvector_push_back(out, 71);
+ ucvector_push_back(out, 13);
+ ucvector_push_back(out, 10);
+ ucvector_push_back(out, 26);
+ ucvector_push_back(out, 10);
+}
+
+static unsigned addChunk_IHDR(ucvector* out, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth, unsigned interlace_method)
+{
+ unsigned error = 0;
+ ucvector header;
+ ucvector_init(&header);
+
+ lodepng_add32bitInt(&header, w); /*width*/
+ lodepng_add32bitInt(&header, h); /*height*/
+ ucvector_push_back(&header, (unsigned char)bitdepth); /*bit depth*/
+ ucvector_push_back(&header, (unsigned char)colortype); /*color type*/
+ ucvector_push_back(&header, 0); /*compression method*/
+ ucvector_push_back(&header, 0); /*filter method*/
+ ucvector_push_back(&header, interlace_method); /*interlace method*/
+
+ error = addChunk(out, "IHDR", header.data, header.size);
+ ucvector_cleanup(&header);
+
+ return error;
+}
+
+static unsigned addChunk_PLTE(ucvector* out, const LodePNGColorMode* info)
+{
+ unsigned error = 0;
+ size_t i;
+ ucvector PLTE;
+ ucvector_init(&PLTE);
+ for(i = 0; i < info->palettesize * 4; i++)
+ {
+ /*add all channels except alpha channel*/
+ if(i % 4 != 3) ucvector_push_back(&PLTE, info->palette[i]);
+ }
+ error = addChunk(out, "PLTE", PLTE.data, PLTE.size);
+ ucvector_cleanup(&PLTE);
+
+ return error;
+}
+
+static unsigned addChunk_tRNS(ucvector* out, const LodePNGColorMode* info)
+{
+ unsigned error = 0;
+ size_t i;
+ ucvector tRNS;
+ ucvector_init(&tRNS);
+ if(info->colortype == LCT_PALETTE)
+ {
+ size_t amount = info->palettesize;
+ /*the tail of palette values that all have 255 as alpha, does not have to be encoded*/
+ for(i = info->palettesize; i > 0; i--)
+ {
+ if(info->palette[4 * (i - 1) + 3] == 255) amount--;
+ else break;
+ }
+ /*add only alpha channel*/
+ for(i = 0; i < amount; i++) ucvector_push_back(&tRNS, info->palette[4 * i + 3]);
+ }
+ else if(info->colortype == LCT_GREY)
+ {
+ if(info->key_defined)
+ {
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256));
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256));
+ }
+ }
+ else if(info->colortype == LCT_RGB)
+ {
+ if(info->key_defined)
+ {
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_r / 256));
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_r % 256));
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_g / 256));
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_g % 256));
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_b / 256));
+ ucvector_push_back(&tRNS, (unsigned char)(info->key_b % 256));
+ }
+ }
+
+ error = addChunk(out, "tRNS", tRNS.data, tRNS.size);
+ ucvector_cleanup(&tRNS);
+
+ return error;
+}
+
+static unsigned addChunk_IDAT(ucvector* out, const unsigned char* data, size_t datasize,
+ LodePNGCompressSettings* zlibsettings)
+{
+ ucvector zlibdata;
+ unsigned error = 0;
+
+ /*compress with the Zlib compressor*/
+ ucvector_init(&zlibdata);
+ error = lodepng_zlib_compress(&zlibdata.data, &zlibdata.size, data, datasize, zlibsettings);
+ if(!error) error = addChunk(out, "IDAT", zlibdata.data, zlibdata.size);
+ ucvector_cleanup(&zlibdata);
+
+ return error;
+}
+
+static unsigned addChunk_IEND(ucvector* out)
+{
+ unsigned error = 0;
+ error = addChunk(out, "IEND", 0, 0);
+ return error;
+}
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+
+static unsigned addChunk_tEXt(ucvector* out, const char* keyword, const char* textstring)
+{
+ unsigned error = 0;
+ size_t i;
+ ucvector text;
+ ucvector_init(&text);
+ for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&text, (unsigned char)keyword[i]);
+ ucvector_push_back(&text, 0);
+ for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&text, (unsigned char)textstring[i]);
+ error = addChunk(out, "tEXt", text.data, text.size);
+ ucvector_cleanup(&text);
+
+ return error;
+}
+
+static unsigned addChunk_zTXt(ucvector* out, const char* keyword, const char* textstring,
+ LodePNGCompressSettings* zlibsettings)
+{
+ unsigned error = 0;
+ ucvector data, compressed;
+ size_t i, textsize = strlen(textstring);
+
+ ucvector_init(&data);
+ ucvector_init(&compressed);
+ for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]);
+ ucvector_push_back(&data, 0); /*0 termination char*/
+ ucvector_push_back(&data, 0); /*compression method: 0*/
+
+ error = lodepng_zlib_compress(&compressed.data, &compressed.size,
+ (unsigned char*)textstring, textsize, zlibsettings);
+ if(!error)
+ {
+ for(i = 0; i < compressed.size; i++) ucvector_push_back(&data, compressed.data[i]);
+ error = addChunk(out, "zTXt", data.data, data.size);
+ }
+
+ ucvector_cleanup(&compressed);
+ ucvector_cleanup(&data);
+ return error;
+}
+
+static unsigned addChunk_iTXt(ucvector* out, unsigned compressed, const char* keyword, const char* langtag,
+ const char* transkey, const char* textstring, LodePNGCompressSettings* zlibsettings)
+{
+ unsigned error = 0;
+ ucvector data;
+ size_t i, textsize = strlen(textstring);
+
+ ucvector_init(&data);
+
+ for(i = 0; keyword[i] != 0; i++) ucvector_push_back(&data, (unsigned char)keyword[i]);
+ ucvector_push_back(&data, 0); /*null termination char*/
+ ucvector_push_back(&data, compressed ? 1 : 0); /*compression flag*/
+ ucvector_push_back(&data, 0); /*compression method*/
+ for(i = 0; langtag[i] != 0; i++) ucvector_push_back(&data, (unsigned char)langtag[i]);
+ ucvector_push_back(&data, 0); /*null termination char*/
+ for(i = 0; transkey[i] != 0; i++) ucvector_push_back(&data, (unsigned char)transkey[i]);
+ ucvector_push_back(&data, 0); /*null termination char*/
+
+ if(compressed)
+ {
+ ucvector compressed_data;
+ ucvector_init(&compressed_data);
+ error = lodepng_zlib_compress(&compressed_data.data, &compressed_data.size,
+ (unsigned char*)textstring, textsize, zlibsettings);
+ if(!error)
+ {
+ for(i = 0; i < compressed_data.size; i++) ucvector_push_back(&data, compressed_data.data[i]);
+ }
+ ucvector_cleanup(&compressed_data);
+ }
+ else /*not compressed*/
+ {
+ for(i = 0; textstring[i] != 0; i++) ucvector_push_back(&data, (unsigned char)textstring[i]);
+ }
+
+ if(!error) error = addChunk(out, "iTXt", data.data, data.size);
+ ucvector_cleanup(&data);
+ return error;
+}
+
+static unsigned addChunk_bKGD(ucvector* out, const LodePNGInfo* info)
+{
+ unsigned error = 0;
+ ucvector bKGD;
+ ucvector_init(&bKGD);
+ if(info->color.colortype == LCT_GREY || info->color.colortype == LCT_GREY_ALPHA)
+ {
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
+ }
+ else if(info->color.colortype == LCT_RGB || info->color.colortype == LCT_RGBA)
+ {
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_r / 256));
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256));
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_g / 256));
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_g % 256));
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_b / 256));
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_b % 256));
+ }
+ else if(info->color.colortype == LCT_PALETTE)
+ {
+ ucvector_push_back(&bKGD, (unsigned char)(info->background_r % 256)); /*palette index*/
+ }
+
+ error = addChunk(out, "bKGD", bKGD.data, bKGD.size);
+ ucvector_cleanup(&bKGD);
+
+ return error;
+}
+
+static unsigned addChunk_tIME(ucvector* out, const LodePNGTime* time)
+{
+ unsigned error = 0;
+ unsigned char* data = (unsigned char*)mymalloc(7);
+ if(!data) return 83; /*alloc fail*/
+ data[0] = (unsigned char)(time->year / 256);
+ data[1] = (unsigned char)(time->year % 256);
+ data[2] = time->month;
+ data[3] = time->day;
+ data[4] = time->hour;
+ data[5] = time->minute;
+ data[6] = time->second;
+ error = addChunk(out, "tIME", data, 7);
+ myfree(data);
+ return error;
+}
+
+static unsigned addChunk_pHYs(ucvector* out, const LodePNGInfo* info)
+{
+ unsigned error = 0;
+ ucvector data;
+ ucvector_init(&data);
+
+ lodepng_add32bitInt(&data, info->phys_x);
+ lodepng_add32bitInt(&data, info->phys_y);
+ ucvector_push_back(&data, info->phys_unit);
+
+ error = addChunk(out, "pHYs", data.data, data.size);
+ ucvector_cleanup(&data);
+
+ return error;
+}
+
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+static void filterScanline(unsigned char* out, const unsigned char* scanline, const unsigned char* prevline,
+ size_t length, size_t bytewidth, unsigned char filterType)
+{
+ size_t i;
+ switch(filterType)
+ {
+ case 0: /*None*/
+ for(i = 0; i < length; i++) out[i] = scanline[i];
+ break;
+ case 1: /*Sub*/
+ if(prevline)
+ {
+ for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
+ for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth];
+ }
+ else
+ {
+ for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
+ for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth];
+ }
+ break;
+ case 2: /*Up*/
+ if(prevline)
+ {
+ for(i = 0; i < length; i++) out[i] = scanline[i] - prevline[i];
+ }
+ else
+ {
+ for(i = 0; i < length; i++) out[i] = scanline[i];
+ }
+ break;
+ case 3: /*Average*/
+ if(prevline)
+ {
+ for(i = 0; i < bytewidth; i++) out[i] = scanline[i] - prevline[i] / 2;
+ for(i = bytewidth; i < length; i++) out[i] = scanline[i] - ((scanline[i - bytewidth] + prevline[i]) / 2);
+ }
+ else
+ {
+ for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
+ for(i = bytewidth; i < length; i++) out[i] = scanline[i] - scanline[i - bytewidth] / 2;
+ }
+ break;
+ case 4: /*Paeth*/
+ if(prevline)
+ {
+ /*paethPredictor(0, prevline[i], 0) is always prevline[i]*/
+ for(i = 0; i < bytewidth; i++) out[i] = (scanline[i] - prevline[i]);
+ for(i = bytewidth; i < length; i++)
+ {
+ out[i] = (scanline[i] - paethPredictor(scanline[i - bytewidth], prevline[i], prevline[i - bytewidth]));
+ }
+ }
+ else
+ {
+ for(i = 0; i < bytewidth; i++) out[i] = scanline[i];
+ /*paethPredictor(scanline[i - bytewidth], 0, 0) is always scanline[i - bytewidth]*/
+ for(i = bytewidth; i < length; i++) out[i] = (scanline[i] - scanline[i - bytewidth]);
+ }
+ break;
+ default: return; /*unexisting filter type given*/
+ }
+}
+
+static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,
+ const LodePNGColorMode* info, const LodePNGEncoderSettings* settings)
+{
+ /*
+ For PNG filter method 0
+ out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
+ the scanlines with 1 extra byte per scanline
+ */
+
+ unsigned bpp = lodepng_get_bpp(info);
+ /*the width of a scanline in bytes, not including the filter type*/
+ size_t linebytes = (w * bpp + 7) / 8;
+ /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
+ size_t bytewidth = (bpp + 7) / 8;
+ const unsigned char* prevline = 0;
+ unsigned x, y;
+ unsigned error = 0;
+ /*
+ There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:
+ * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e.
+ use fixed filtering, with the filter None).
+ * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is
+ not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply
+ all five filters and select the filter that produces the smallest sum of absolute values per row.
+ This heuristic is used if filter strategy is LFS_HEURISTIC. Parts of it are used for filter strategies
+ LFS_MINSUM and LFS_ZERO.
+ */
+ int heuristic_zero = info->colortype == LCT_PALETTE || info->bitdepth < 8;
+
+ if(bpp == 0) return 31; /*error: invalid color type*/
+
+ if((!heuristic_zero && settings->filter_strategy == LFS_HEURISTIC)||
+ settings->filter_strategy == LFS_MINSUM)
+ {
+ /*adaptive filtering*/
+ size_t sum[5];
+ ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
+ size_t smallest = 0;
+ unsigned type, bestType = 0;
+
+ for(type = 0; type < 5; type++) ucvector_init(&attempt[type]);
+
+ for(type = 0; type < 5; type++)
+ {
+ if(!ucvector_resize(&attempt[type], linebytes)) ERROR_BREAK(83 /*alloc fail*/);
+ }
+
+ if(!error)
+ {
+ for(y = 0; y < h; y++)
+ {
+ /*try the 5 filter types*/
+ for(type = 0; type < 5; type++)
+ {
+ filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
+
+ /*calculate the sum of the result*/
+ sum[type] = 0;
+ /*note that not all pixels are checked to speed this up while still having probably the best choice*/
+ for(x = 0; x < attempt[type].size; x+=3)
+ {
+ /*For differences, each byte should be treated as signed, values above 127 are negative
+ (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.
+ This means filtertype 0 is almost never chosen, but that is justified.*/
+ if(type == 0) sum[type] += (unsigned char)(attempt[type].data[x]);
+ else
+ {
+ signed char s = (signed char)(attempt[type].data[x]);
+ sum[type] += s < 0 ? -s : s;
+ }
+ }
+
+ /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
+ if(type == 0 || sum[type] < smallest)
+ {
+ bestType = type;
+ smallest = sum[type];
+ }
+ }
+
+ prevline = &in[y * linebytes];
+
+ /*now fill the out values*/
+ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
+ for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
+ }
+ }
+
+ for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
+ }
+ else if((heuristic_zero && settings->filter_strategy == LFS_HEURISTIC)||
+ settings->filter_strategy == LFS_ZERO)
+ {
+ for(y = 0; y < h; y++)
+ {
+ size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
+ size_t inindex = linebytes * y;
+ const unsigned TYPE = 0;
+ out[outindex] = TYPE; /*filter type byte*/
+ filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, TYPE);
+ prevline = &in[inindex];
+ }
+ }
+ else if(settings->filter_strategy == LFS_PREDEFINED)
+ {
+ for(y = 0; y < h; y++)
+ {
+ size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
+ size_t inindex = linebytes * y;
+ unsigned type = settings->predefined_filters[y];
+ out[outindex] = type; /*filter type byte*/
+ filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
+ prevline = &in[inindex];
+ }
+ }
+ else /*LFS_BRUTE_FORCE*/
+ {
+ /*brute force filter chooser.
+ deflate the scanline after every filter attempt to see which one deflates best.
+ This is very slow and gives only slightly smaller, sometimes even larger, result*/
+ size_t size[5];
+ ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
+ size_t smallest = 0;
+ unsigned type = 0, bestType = 0;
+ unsigned char* dummy;
+ LodePNGCompressSettings zlibsettings = settings->zlibsettings;
+ /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,
+ to simulate the true case where the tree is the same for the whole image. Sometimes it gives
+ better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare
+ cases better compression. It does make this a bit less slow, so it's worth doing this.*/
+ zlibsettings.btype = 1;
+ /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG
+ images only, so disable it*/
+ zlibsettings.custom_encoder = 0;
+ for(type = 0; type < 5; type++)
+ {
+ ucvector_init(&attempt[type]);
+ ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/
+ }
+ for(y = 0; y < h; y++) /*try the 5 filter types*/
+ {
+ for(type = 0; type < 5; type++)
+ {
+ unsigned testsize = attempt[type].size;
+ /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/
+
+ filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
+ size[type] = 0;
+ dummy = 0;
+ lodepng_zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings);
+ myfree(dummy);
+ /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
+ if(type == 0 || size[type] < smallest)
+ {
+ bestType = type;
+ smallest = size[type];
+ }
+ }
+ prevline = &in[y * linebytes];
+ out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
+ for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
+ }
+ for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
+ }
+
+ return error;
+}
+
+static void addPaddingBits(unsigned char* out, const unsigned char* in,
+ size_t olinebits, size_t ilinebits, unsigned h)
+{
+ /*The opposite of the removePaddingBits function
+ olinebits must be >= ilinebits*/
+ unsigned y;
+ size_t diff = olinebits - ilinebits;
+ size_t obp = 0, ibp = 0; /*bit pointers*/
+ for(y = 0; y < h; y++)
+ {
+ size_t x;
+ for(x = 0; x < ilinebits; x++)
+ {
+ unsigned char bit = readBitFromReversedStream(&ibp, in);
+ setBitOfReversedStream(&obp, out, bit);
+ }
+ /*obp += diff; --> no, fill in some value in the padding bits too, to avoid
+ "Use of uninitialised value of size ###" warning from valgrind*/
+ for(x = 0; x < diff; x++) setBitOfReversedStream(&obp, out, 0);
+ }
+}
+
+static void Adam7_interlace(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, unsigned bpp)
+{
+ /*Note: this function works on image buffers WITHOUT padding bits at end of scanlines with non-multiple-of-8
+ bit amounts, only between reduced images is padding*/
+ unsigned passw[7], passh[7];
+ size_t filter_passstart[8], padded_passstart[8], passstart[8];
+ unsigned i;
+
+ Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+ if(bpp >= 8)
+ {
+ for(i = 0; i < 7; i++)
+ {
+ unsigned x, y, b;
+ size_t bytewidth = bpp / 8;
+ for(y = 0; y < passh[i]; y++)
+ for(x = 0; x < passw[i]; x++)
+ {
+ size_t pixelinstart = ((ADAM7_IY[i] + y * ADAM7_DY[i]) * w + ADAM7_IX[i] + x * ADAM7_DX[i]) * bytewidth;
+ size_t pixeloutstart = passstart[i] + (y * passw[i] + x) * bytewidth;
+ for(b = 0; b < bytewidth; b++)
+ {
+ out[pixeloutstart + b] = in[pixelinstart + b];
+ }
+ }
+ }
+ }
+ else /*bpp < 8: Adam7 with pixels < 8 bit is a bit trickier: with bit pointers*/
+ {
+ for(i = 0; i < 7; i++)
+ {
+ unsigned x, y, b;
+ unsigned ilinebits = bpp * passw[i];
+ unsigned olinebits = bpp * w;
+ size_t obp, ibp; /*bit pointers (for out and in buffer)*/
+ for(y = 0; y < passh[i]; y++)
+ for(x = 0; x < passw[i]; x++)
+ {
+ ibp = (ADAM7_IY[i] + y * ADAM7_DY[i]) * olinebits + (ADAM7_IX[i] + x * ADAM7_DX[i]) * bpp;
+ obp = (8 * passstart[i]) + (y * ilinebits + x * bpp);
+ for(b = 0; b < bpp; b++)
+ {
+ unsigned char bit = readBitFromReversedStream(&ibp, in);
+ setBitOfReversedStream(&obp, out, bit);
+ }
+ }
+ }
+ }
+}
+
+/*out must be buffer big enough to contain uncompressed IDAT chunk data, and in must contain the full image.
+return value is error**/
+static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const unsigned char* in,
+ unsigned w, unsigned h,
+ const LodePNGInfo* info_png, const LodePNGEncoderSettings* settings)
+{
+ /*
+ This function converts the pure 2D image with the PNG's colortype, into filtered-padded-interlaced data. Steps:
+ *) if no Adam7: 1) add padding bits (= posible extra bits per scanline if bpp < 8) 2) filter
+ *) if adam7: 1) Adam7_interlace 2) 7x add padding bits 3) 7x filter
+ */
+ unsigned bpp = lodepng_get_bpp(&info_png->color);
+ unsigned error = 0;
+
+ if(info_png->interlace_method == 0)
+ {
+ *outsize = h + (h * ((w * bpp + 7) / 8)); /*image size plus an extra byte per scanline + possible padding bits*/
+ *out = (unsigned char*)mymalloc(*outsize);
+ if(!(*out) && (*outsize)) error = 83; /*alloc fail*/
+
+ if(!error)
+ {
+ /*non multiple of 8 bits per scanline, padding bits needed per scanline*/
+ if(bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8)
+ {
+ ucvector padded;
+ ucvector_init(&padded);
+ if(!ucvector_resize(&padded, h * ((w * bpp + 7) / 8))) error = 83; /*alloc fail*/
+ if(!error)
+ {
+ addPaddingBits(padded.data, in, ((w * bpp + 7) / 8) * 8, w * bpp, h);
+ error = filter(*out, padded.data, w, h, &info_png->color, settings);
+ }
+ ucvector_cleanup(&padded);
+ }
+ else
+ {
+ /*we can immediatly filter into the out buffer, no other steps needed*/
+ error = filter(*out, in, w, h, &info_png->color, settings);
+ }
+ }
+ }
+ else /*interlace_method is 1 (Adam7)*/
+ {
+ unsigned char* adam7 = (unsigned char*)mymalloc((h * w * bpp + 7) / 8);
+ if(!adam7 && ((h * w * bpp + 7) / 8)) error = 83; /*alloc fail*/
+
+ while(!error) /*not a real while loop, used to break out to cleanup to avoid a goto*/
+ {
+ unsigned passw[7], passh[7];
+ size_t filter_passstart[8], padded_passstart[8], passstart[8];
+ unsigned i;
+
+ Adam7_getpassvalues(passw, passh, filter_passstart, padded_passstart, passstart, w, h, bpp);
+
+ *outsize = filter_passstart[7]; /*image size plus an extra byte per scanline + possible padding bits*/
+ *out = (unsigned char*)mymalloc(*outsize);
+ if(!(*out) && (*outsize)) ERROR_BREAK(83 /*alloc fail*/);
+
+ Adam7_interlace(adam7, in, w, h, bpp);
+
+ for(i = 0; i < 7; i++)
+ {
+ if(bpp < 8)
+ {
+ ucvector padded;
+ ucvector_init(&padded);
+ if(!ucvector_resize(&padded, h * ((w * bpp + 7) / 8))) error = 83; /*alloc fail*/
+ if(!error)
+ {
+ addPaddingBits(&padded.data[padded_passstart[i]], &adam7[passstart[i]],
+ ((passw[i] * bpp + 7) / 8) * 8, passw[i] * bpp, passh[i]);
+ error = filter(&(*out)[filter_passstart[i]], &padded.data[padded_passstart[i]],
+ passw[i], passh[i], &info_png->color, settings);
+ }
+
+ ucvector_cleanup(&padded);
+ }
+ else
+ {
+ error = filter(&(*out)[filter_passstart[i]], &adam7[padded_passstart[i]],
+ passw[i], passh[i], &info_png->color, settings);
+ }
+ }
+
+ break;
+ }
+
+ myfree(adam7);
+ }
+
+ return error;
+}
+
+/*
+palette must have 4 * palettesize bytes allocated, and given in format RGBARGBARGBARGBA...
+returns 0 if the palette is opaque,
+returns 1 if the palette has a single color with alpha 0 ==> color key
+returns 2 if the palette is semi-translucent.
+*/
+static unsigned getPaletteTranslucency(const unsigned char* palette, size_t palettesize)
+{
+ size_t i, key = 0;
+ unsigned r, g, b; /*the value of the color with alpha 0, so long as color keying is possible*/
+ for(i = 0; i < palettesize; i++)
+ {
+ if(!key && palette[4 * i + 3] == 0)
+ {
+ r = palette[4 * i + 0]; g = palette[4 * i + 1]; b = palette[4 * i + 2];
+ key = 1;
+ i = (size_t)(-1); /*restart from beginning, to detect earlier opaque colors with key's value*/
+ }
+ else if(palette[4 * i + 3] != 255) return 2;
+ /*when key, no opaque RGB may have key's RGB*/
+ else if(key && r == palette[i * 4 + 0] && g == palette[i * 4 + 1] && b == palette[i * 4 + 2]) return 2;
+ }
+ return key;
+}
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+static unsigned addUnknownChunks(ucvector* out, unsigned char* data, size_t datasize)
+{
+ unsigned char* inchunk = data;
+ while((size_t)(inchunk - data) < datasize)
+ {
+ CERROR_TRY_RETURN(lodepng_chunk_append(&out->data, &out->size, inchunk));
+ out->allocsize = out->size; /*fix the allocsize again*/
+ inchunk = lodepng_chunk_next(inchunk);
+ }
+ return 0;
+}
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+unsigned lodepng_encode(unsigned char** out, size_t* outsize,
+ const unsigned char* image, unsigned w, unsigned h,
+ LodePNGState* state)
+{
+ LodePNGInfo info;
+ ucvector outv;
+ unsigned char* data = 0; /*uncompressed version of the IDAT chunk data*/
+ size_t datasize = 0;
+
+ /*provide some proper output values if error will happen*/
+ *out = 0;
+ *outsize = 0;
+ state->error = 0;
+
+ lodepng_info_init(&info);
+ lodepng_info_copy(&info, &state->info_png);
+
+ if((info.color.colortype == LCT_PALETTE || state->encoder.force_palette)
+ && (info.color.palettesize == 0 || info.color.palettesize > 256))
+ {
+ state->error = 68; /*invalid palette size, it is only allowed to be 1-256*/
+ return state->error;
+ }
+
+ if(state->encoder.auto_convert != LAC_NO)
+ {
+ state->error = doAutoChooseColor(&info.color, image, w, h, &state->info_raw,
+ state->encoder.auto_convert);
+ }
+ if(state->error) return state->error;
+
+ if(state->encoder.zlibsettings.windowsize > 32768)
+ {
+ CERROR_RETURN_ERROR(state->error, 60); /*error: windowsize larger than allowed*/
+ }
+ if(state->encoder.zlibsettings.btype > 2)
+ {
+ CERROR_RETURN_ERROR(state->error, 61); /*error: unexisting btype*/
+ }
+ if(state->info_png.interlace_method > 1)
+ {
+ CERROR_RETURN_ERROR(state->error, 71); /*error: unexisting interlace mode*/
+ }
+ /*error: unexisting color type given*/
+ if((state->error = checkColorValidity(info.color.colortype, info.color.bitdepth))) return state->error;
+ /*error: unexisting color type given*/
+ if((state->error = checkColorValidity(state->info_raw.colortype, state->info_raw.bitdepth))) return state->error;
+
+ if(!lodepng_color_mode_equal(&state->info_raw, &info.color))
+ {
+ unsigned char* converted;
+ size_t size = (w * h * lodepng_get_bpp(&info.color) + 7) / 8;
+
+ converted = (unsigned char*)mymalloc(size);
+ if(!converted && size) state->error = 83; /*alloc fail*/
+ if(!state->error)
+ {
+ state->error = lodepng_convert(converted, image, &info.color, &state->info_raw, w, h);
+ }
+ if(!state->error) preProcessScanlines(&data, &datasize, converted, w, h, &info, &state->encoder);
+ myfree(converted);
+ }
+ else preProcessScanlines(&data, &datasize, image, w, h, &info, &state->encoder);
+
+ ucvector_init(&outv);
+ while(!state->error) /*while only executed once, to break on error*/
+ {
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ size_t i;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ /*write signature and chunks*/
+ writeSignature(&outv);
+ /*IHDR*/
+ addChunk_IHDR(&outv, w, h, info.color.colortype, info.color.bitdepth, info.interlace_method);
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ /*unknown chunks between IHDR and PLTE*/
+ if(info.unknown_chunks_data[0])
+ {
+ state->error = addUnknownChunks(&outv, info.unknown_chunks_data[0], info.unknown_chunks_size[0]);
+ if(state->error) break;
+ }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ /*PLTE*/
+ if(info.color.colortype == LCT_PALETTE)
+ {
+ addChunk_PLTE(&outv, &info.color);
+ }
+ if(state->encoder.force_palette && (info.color.colortype == LCT_RGB || info.color.colortype == LCT_RGBA))
+ {
+ addChunk_PLTE(&outv, &info.color);
+ }
+ /*tRNS*/
+ if(info.color.colortype == LCT_PALETTE && getPaletteTranslucency(info.color.palette, info.color.palettesize) != 0)
+ {
+ addChunk_tRNS(&outv, &info.color);
+ }
+ if((info.color.colortype == LCT_GREY || info.color.colortype == LCT_RGB) && info.color.key_defined)
+ {
+ addChunk_tRNS(&outv, &info.color);
+ }
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ /*bKGD (must come between PLTE and the IDAt chunks*/
+ if(info.background_defined) addChunk_bKGD(&outv, &info);
+ /*pHYs (must come before the IDAT chunks)*/
+ if(info.phys_defined) addChunk_pHYs(&outv, &info);
+
+ /*unknown chunks between PLTE and IDAT*/
+ if(info.unknown_chunks_data[1])
+ {
+ state->error = addUnknownChunks(&outv, info.unknown_chunks_data[1], info.unknown_chunks_size[1]);
+ if(state->error) break;
+ }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ /*IDAT (multiple IDAT chunks must be consecutive)*/
+ state->error = addChunk_IDAT(&outv, data, datasize, &state->encoder.zlibsettings);
+ if(state->error) break;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ /*tIME*/
+ if(info.time_defined) addChunk_tIME(&outv, &info.time);
+ /*tEXt and/or zTXt*/
+ for(i = 0; i < info.text_num; i++)
+ {
+ if(strlen(info.text_keys[i]) > 79)
+ {
+ state->error = 66; /*text chunk too large*/
+ break;
+ }
+ if(strlen(info.text_keys[i]) < 1)
+ {
+ state->error = 67; /*text chunk too small*/
+ break;
+ }
+ if(state->encoder.text_compression)
+ addChunk_zTXt(&outv, info.text_keys[i], info.text_strings[i], &state->encoder.zlibsettings);
+ else
+ addChunk_tEXt(&outv, info.text_keys[i], info.text_strings[i]);
+ }
+ /*LodePNG version id in text chunk*/
+ if(state->encoder.add_id)
+ {
+ unsigned alread_added_id_text = 0;
+ for(i = 0; i < info.text_num; i++)
+ {
+ if(!strcmp(info.text_keys[i], "LodePNG"))
+ {
+ alread_added_id_text = 1;
+ break;
+ }
+ }
+ if(alread_added_id_text == 0)
+ addChunk_tEXt(&outv, "LodePNG", VERSION_STRING); /*it's shorter as tEXt than as zTXt chunk*/
+ }
+ /*iTXt*/
+ for(i = 0; i < info.itext_num; i++)
+ {
+ if(strlen(info.itext_keys[i]) > 79)
+ {
+ state->error = 66; /*text chunk too large*/
+ break;
+ }
+ if(strlen(info.itext_keys[i]) < 1)
+ {
+ state->error = 67; /*text chunk too small*/
+ break;
+ }
+ addChunk_iTXt(&outv, state->encoder.text_compression,
+ info.itext_keys[i], info.itext_langtags[i], info.itext_transkeys[i], info.itext_strings[i],
+ &state->encoder.zlibsettings);
+ }
+
+ /*unknown chunks between IDAT and IEND*/
+ if(info.unknown_chunks_data[2])
+ {
+ state->error = addUnknownChunks(&outv, info.unknown_chunks_data[2], info.unknown_chunks_size[2]);
+ if(state->error) break;
+ }
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+ /*IEND*/
+ addChunk_IEND(&outv);
+
+ break; /*this isn't really a while loop; no error happened so break out now!*/
+ }
+
+ lodepng_info_cleanup(&info);
+ myfree(data);
+ /*instead of cleaning the vector up, give it to the output*/
+ *out = outv.data;
+ *outsize = outv.size;
+
+ return state->error;
+}
+
+unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize, const unsigned char* image,
+ unsigned w, unsigned h, LodePNGColorType colortype, unsigned bitdepth)
+{
+ unsigned error;
+ LodePNGState state;
+ lodepng_state_init(&state);
+ state.info_raw.colortype = colortype;
+ state.info_raw.bitdepth = bitdepth;
+ state.info_png.color.colortype = colortype;
+ state.info_png.color.bitdepth = bitdepth;
+ lodepng_encode(out, outsize, image, w, h, &state);
+ error = state.error;
+ lodepng_state_cleanup(&state);
+ return error;
+}
+
+unsigned lodepng_encode32(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
+{
+ return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGBA, 8);
+}
+
+unsigned lodepng_encode24(unsigned char** out, size_t* outsize, const unsigned char* image, unsigned w, unsigned h)
+{
+ return lodepng_encode_memory(out, outsize, image, w, h, LCT_RGB, 8);
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned lodepng_encode_file(const char* filename, const unsigned char* image, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth)
+{
+ unsigned char* buffer;
+ size_t buffersize;
+ unsigned error = lodepng_encode_memory(&buffer, &buffersize, image, w, h, colortype, bitdepth);
+ if(!error) error = lodepng_save_file(buffer, buffersize, filename);
+ myfree(buffer);
+ return error;
+}
+
+unsigned lodepng_encode32_file(const char* filename, const unsigned char* image, unsigned w, unsigned h)
+{
+ return lodepng_encode_file(filename, image, w, h, LCT_RGBA, 8);
+}
+
+unsigned lodepng_encode24_file(const char* filename, const unsigned char* image, unsigned w, unsigned h)
+{
+ return lodepng_encode_file(filename, image, w, h, LCT_RGB, 8);
+}
+#endif /*LODEPNG_COMPILE_DISK*/
+
+void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings)
+{
+ lodepng_compress_settings_init(&settings->zlibsettings);
+ settings->filter_strategy = LFS_HEURISTIC;
+ settings->auto_convert = LAC_AUTO;
+ settings->force_palette = 0;
+ settings->predefined_filters = 0;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ settings->add_id = 0;
+ settings->text_compression = 1;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+}
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+#ifdef LODEPNG_COMPILE_ERROR_TEXT
+/*
+This returns the description of a numerical error code in English. This is also
+the documentation of all the error codes.
+*/
+const char* lodepng_error_text(unsigned code)
+{
+ switch(code)
+ {
+ case 0: return "no error, everything went ok";
+ case 1: return "nothing done yet"; /*the Encoder/Decoder has done nothing yet, error checking makes no sense yet*/
+ case 10: return "end of input memory reached without huffman end code"; /*while huffman decoding*/
+ case 11: return "error in code tree made it jump outside of huffman tree"; /*while huffman decoding*/
+ case 13: return "problem while processing dynamic deflate block";
+ case 14: return "problem while processing dynamic deflate block";
+ case 15: return "problem while processing dynamic deflate block";
+ case 16: return "unexisting code while processing dynamic deflate block";
+ case 17: return "end of out buffer memory reached while inflating";
+ case 18: return "invalid distance code while inflating";
+ case 19: return "end of out buffer memory reached while inflating";
+ case 20: return "invalid deflate block BTYPE encountered while decoding";
+ case 21: return "NLEN is not ones complement of LEN in a deflate block";
+
+ /*end of out buffer memory reached while inflating:
+ This can happen if the inflated deflate data is longer than the amount of bytes required to fill up
+ all the pixels of the image, given the color depth and image dimensions. Something that doesn't
+ happen in a normal, well encoded, PNG image.*/
+ case 22: return "end of out buffer memory reached while inflating";
+
+ case 23: return "end of in buffer memory reached while inflating";
+ case 24: return "invalid FCHECK in zlib header";
+ case 25: return "invalid compression method in zlib header";
+ case 26: return "FDICT encountered in zlib header while it's not used for PNG";
+ case 27: return "PNG file is smaller than a PNG header";
+ /*Checks the magic file header, the first 8 bytes of the PNG file*/
+ case 28: return "incorrect PNG signature, it's no PNG or corrupted";
+ case 29: return "first chunk is not the header chunk";
+ case 30: return "chunk length too large, chunk broken off at end of file";
+ case 31: return "illegal PNG color type or bpp";
+ case 32: return "illegal PNG compression method";
+ case 33: return "illegal PNG filter method";
+ case 34: return "illegal PNG interlace method";
+ case 35: return "chunk length of a chunk is too large or the chunk too small";
+ case 36: return "illegal PNG filter type encountered";
+ case 37: return "illegal bit depth for this color type given";
+ case 38: return "the palette is too big"; /*more than 256 colors*/
+ case 39: return "more palette alpha values given in tRNS chunk than there are colors in the palette";
+ case 40: return "tRNS chunk has wrong size for greyscale image";
+ case 41: return "tRNS chunk has wrong size for RGB image";
+ case 42: return "tRNS chunk appeared while it was not allowed for this color type";
+ case 43: return "bKGD chunk has wrong size for palette image";
+ case 44: return "bKGD chunk has wrong size for greyscale image";
+ case 45: return "bKGD chunk has wrong size for RGB image";
+ /*Is the palette too small?*/
+ case 46: return "a value in indexed image is larger than the palette size (bitdepth = 8)";
+ /*Is the palette too small?*/
+ case 47: return "a value in indexed image is larger than the palette size (bitdepth < 8)";
+ /*the input data is empty, maybe a PNG file doesn't exist or is in the wrong path*/
+ case 48: return "empty input or file doesn't exist";
+ case 49: return "jumped past memory while generating dynamic huffman tree";
+ case 50: return "jumped past memory while generating dynamic huffman tree";
+ case 51: return "jumped past memory while inflating huffman block";
+ case 52: return "jumped past memory while inflating";
+ case 53: return "size of zlib data too small";
+ case 54: return "repeat symbol in tree while there was no value symbol yet";
+
+ /*jumped past tree while generating huffman tree, this could be when the
+ tree will have more leaves than symbols after generating it out of the
+ given lenghts. They call this an oversubscribed dynamic bit lengths tree in zlib.*/
+ case 55: return "jumped past tree while generating huffman tree";
+
+ case 56: return "given output image colortype or bitdepth not supported for color conversion";
+ case 57: return "invalid CRC encountered (checking CRC can be disabled)";
+ case 58: return "invalid ADLER32 encountered (checking ADLER32 can be disabled)";
+ case 59: return "requested color conversion not supported";
+ case 60: return "invalid window size given in the settings of the encoder (must be 0-32768)";
+ case 61: return "invalid BTYPE given in the settings of the encoder (only 0, 1 and 2 are allowed)";
+ /*LodePNG leaves the choice of RGB to greyscale conversion formula to the user.*/
+ case 62: return "conversion from color to greyscale not supported";
+ case 63: return "length of a chunk too long, max allowed for PNG is 2147483647 bytes per chunk"; /*(2^31-1)*/
+ /*this would result in the inability of a deflated block to ever contain an end code. It must be at least 1.*/
+ case 64: return "the length of the END symbol 256 in the Huffman tree is 0";
+ case 66: return "the length of a text chunk keyword given to the encoder is longer than the maximum of 79 bytes";
+ case 67: return "the length of a text chunk keyword given to the encoder is smaller than the minimum of 1 byte";
+ case 68: return "tried to encode a PLTE chunk with a palette that has less than 1 or more than 256 colors";
+ case 69: return "unknown chunk type with 'critical' flag encountered by the decoder";
+ case 71: return "unexisting interlace mode given to encoder (must be 0 or 1)";
+ case 72: return "while decoding, unexisting compression method encountering in zTXt or iTXt chunk (it must be 0)";
+ case 73: return "invalid tIME chunk size";
+ case 74: return "invalid pHYs chunk size";
+ /*length could be wrong, or data chopped off*/
+ case 75: return "no null termination char found while decoding text chunk";
+ case 76: return "iTXt chunk too short to contain required bytes";
+ case 77: return "integer overflow in buffer size";
+ case 78: return "failed to open file for reading"; /*file doesn't exist or couldn't be opened for reading*/
+ case 79: return "failed to open file for writing";
+ case 80: return "tried creating a tree of 0 symbols";
+ case 81: return "lazy matching at pos 0 is impossible";
+ case 82: return "color conversion to palette requested while a color isn't in palette";
+ case 83: return "memory allocation failed";
+ case 84: return "given image too small to contain all pixels to be encoded";
+ case 85: return "internal color conversion bug";
+ case 86: return "impossible offset in lz77 encoding (internal bug)";
+ }
+ return "unknown error code";
+}
+#endif /*LODEPNG_COMPILE_ERROR_TEXT*/
+
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* // C++ Wrapper // */
+/* ////////////////////////////////////////////////////////////////////////// */
+/* ////////////////////////////////////////////////////////////////////////// */
+
+
+#ifdef LODEPNG_COMPILE_CPP
+namespace lodepng
+{
+
+#ifdef LODEPNG_COMPILE_DISK
+void load_file(std::vector<unsigned char>& buffer, const std::string& filename)
+{
+ std::ifstream file(filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
+
+ /*get filesize*/
+ std::streamsize size = 0;
+ if(file.seekg(0, std::ios::end).good()) size = file.tellg();
+ if(file.seekg(0, std::ios::beg).good()) size -= file.tellg();
+
+ /*read contents of the file into the vector*/
+ buffer.resize(size_t(size));
+ if(size > 0) file.read((char*)(&buffer[0]), size);
+}
+
+/*write given buffer to the file, overwriting the file, it doesn't append to it.*/
+void save_file(const std::vector<unsigned char>& buffer, const std::string& filename)
+{
+ std::ofstream file(filename.c_str(), std::ios::out|std::ios::binary);
+ file.write(buffer.empty() ? 0 : (char*)&buffer[0], std::streamsize(buffer.size()));
+}
+#endif //LODEPNG_COMPILE_DISK
+
+#ifdef LODEPNG_COMPILE_ZLIB
+#ifdef LODEPNG_COMPILE_DECODER
+unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings& settings)
+{
+ unsigned char* buffer = 0;
+ size_t buffersize = 0;
+ unsigned error = lodepng_zlib_decompress(&buffer, &buffersize, in, insize, &settings);
+ if(buffer)
+ {
+ out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ myfree(buffer);
+ }
+ return error;
+}
+
+unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+ const LodePNGDecompressSettings& settings)
+{
+ return decompress(out, in.empty() ? 0 : &in[0], in.size(), settings);
+}
+#endif //LODEPNG_COMPILE_DECODER
+
+#ifdef LODEPNG_COMPILE_ENCODER
+unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings& settings)
+{
+ unsigned char* buffer = 0;
+ size_t buffersize = 0;
+ unsigned error = lodepng_zlib_compress(&buffer, &buffersize, in, insize, &settings);
+ if(buffer)
+ {
+ out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ myfree(buffer);
+ }
+ return error;
+}
+
+unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+ const LodePNGCompressSettings& settings)
+{
+ return compress(out, in.empty() ? 0 : &in[0], in.size(), settings);
+}
+#endif //LODEPNG_COMPILE_ENCODER
+#endif //LODEPNG_COMPILE_ZLIB
+
+
+#ifdef LODEPNG_COMPILE_PNG
+
+State::State()
+{
+ lodepng_state_init(this);
+}
+
+State::State(const State& other)
+{
+ lodepng_state_init(this);
+ lodepng_state_copy(this, &other);
+}
+
+State::~State()
+{
+ lodepng_state_cleanup(this);
+}
+
+State& State::operator=(const State& other)
+{
+ lodepng_state_copy(this, &other);
+ return *this;
+}
+
+#ifdef LODEPNG_COMPILE_DECODER
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const unsigned char* in,
+ size_t insize, LodePNGColorType colortype, unsigned bitdepth)
+{
+ unsigned char* buffer;
+ unsigned error = lodepng_decode_memory(&buffer, &w, &h, in, insize, colortype, bitdepth);
+ if(buffer && !error)
+ {
+ State state;
+ state.info_raw.colortype = colortype;
+ state.info_raw.bitdepth = bitdepth;
+ size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
+ out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ myfree(buffer);
+ }
+ return error;
+}
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ const std::vector<unsigned char>& in, LodePNGColorType colortype, unsigned bitdepth)
+{
+ return decode(out, w, h, in.empty() ? 0 : &in[0], (unsigned)in.size(), colortype, bitdepth);
+}
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ State& state,
+ const unsigned char* in, size_t insize)
+{
+ unsigned char* buffer;
+ unsigned error = lodepng_decode(&buffer, &w, &h, &state, in, insize);
+ if(buffer && !error)
+ {
+ size_t buffersize = lodepng_get_raw_size(w, h, &state.info_raw);
+ out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ myfree(buffer);
+ }
+ return error;
+}
+
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ State& state,
+ const std::vector<unsigned char>& in)
+{
+ return decode(out, w, h, state, in.empty() ? 0 : &in[0], in.size());
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h, const std::string& filename,
+ LodePNGColorType colortype, unsigned bitdepth)
+{
+ std::vector<unsigned char> buffer;
+ load_file(buffer, filename);
+ return decode(out, w, h, buffer, colortype, bitdepth);
+}
+#endif //LODEPNG_COMPILE_DECODER
+#endif //LODEPNG_COMPILE_DISK
+
+#ifdef LODEPNG_COMPILE_ENCODER
+unsigned encode(std::vector<unsigned char>& out, const unsigned char* in, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth)
+{
+ unsigned char* buffer;
+ size_t buffersize;
+ unsigned error = lodepng_encode_memory(&buffer, &buffersize, in, w, h, colortype, bitdepth);
+ if(buffer)
+ {
+ out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ myfree(buffer);
+ }
+ return error;
+}
+
+unsigned encode(std::vector<unsigned char>& out,
+ const std::vector<unsigned char>& in, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth)
+{
+ if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
+ return encode(out, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
+}
+
+unsigned encode(std::vector<unsigned char>& out,
+ const unsigned char* in, unsigned w, unsigned h,
+ State& state)
+{
+ unsigned char* buffer;
+ size_t buffersize;
+ unsigned error = lodepng_encode(&buffer, &buffersize, in, w, h, &state);
+ if(buffer)
+ {
+ out.insert(out.end(), &buffer[0], &buffer[buffersize]);
+ myfree(buffer);
+ }
+ return error;
+}
+
+unsigned encode(std::vector<unsigned char>& out,
+ const std::vector<unsigned char>& in, unsigned w, unsigned h,
+ State& state)
+{
+ if(lodepng_get_raw_size(w, h, &state.info_raw) > in.size()) return 84;
+ return encode(out, in.empty() ? 0 : &in[0], w, h, state);
+}
+
+#ifdef LODEPNG_COMPILE_DISK
+unsigned encode(const std::string& filename,
+ const unsigned char* in, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth)
+{
+ std::vector<unsigned char> buffer;
+ unsigned error = encode(buffer, in, w, h, colortype, bitdepth);
+ if(!error) save_file(buffer, filename);
+ return error;
+}
+
+unsigned encode(const std::string& filename,
+ const std::vector<unsigned char>& in, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth)
+{
+ if(lodepng_get_raw_size_lct(w, h, colortype, bitdepth) > in.size()) return 84;
+ return encode(filename, in.empty() ? 0 : &in[0], w, h, colortype, bitdepth);
+}
+#endif //LODEPNG_COMPILE_DISK
+#endif //LODEPNG_COMPILE_ENCODER
+#endif //LODEPNG_COMPILE_PNG
+} //namespace lodepng
+#endif /*LODEPNG_COMPILE_CPP*/
diff --git a/lib/lodepng.h b/lib/lodepng.h
new file mode 100644
index 0000000000..50d5303055
--- /dev/null
+++ b/lib/lodepng.h
@@ -0,0 +1,1640 @@
+/*
+LodePNG version 20120729
+
+Copyright (c) 2005-2012 Lode Vandevenne
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
+*/
+
+#ifndef LODEPNG_H
+#define LODEPNG_H
+
+#define LODEPNG_NO_COMPILE_ENCODER
+#define LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
+#define LODEPNG_NO_COMPILE_CPP
+#define LODEPNG_NO_COMPILE_DISK
+#define LODEPNG_NO_COMPILE_ZLIB
+#define LODEPNG_NO_COMPILE_CPP
+
+#include <string.h> /*for size_t*/
+
+#ifdef __cplusplus
+#include <vector>
+#include <string>
+#endif /*__cplusplus*/
+
+/*
+The following #defines are used to create code sections. They can be disabled
+to disable code sections, which can give faster compile time and smaller binary.
+The "NO_COMPILE" defines are designed to be used to pass as defines to the
+compiler command to disable them without modifying this header, e.g.
+-DLODEPNG_NO_COMPILE_ZLIB for gcc.
+*/
+/*deflate&zlib. If disabled, you need to define two zlib functions, see documtation of LODEPNG_CUSTOM_ZLIB_... below*/
+#ifndef LODEPNG_NO_COMPILE_ZLIB
+#define LODEPNG_COMPILE_ZLIB
+#endif
+/*png encoder and png decoder*/
+#ifndef LODEPNG_NO_COMPILE_PNG
+#define LODEPNG_COMPILE_PNG
+#endif
+/*deflate&zlib decoder and png decoder*/
+#ifndef LODEPNG_NO_COMPILE_DECODER
+#define LODEPNG_COMPILE_DECODER
+#endif
+/*deflate&zlib encoder and png encoder*/
+#ifndef LODEPNG_NO_COMPILE_ENCODER
+#define LODEPNG_COMPILE_ENCODER
+#endif
+/*the optional built in harddisk file loading and saving functions*/
+#ifndef LODEPNG_NO_COMPILE_DISK
+#define LODEPNG_COMPILE_DISK
+#endif
+/*support for chunks other than IHDR, IDAT, PLTE, tRNS, IEND: ancillary and unknown chunks*/
+#ifndef LODEPNG_NO_COMPILE_ANCILLARY_CHUNKS
+#define LODEPNG_COMPILE_ANCILLARY_CHUNKS
+#endif
+/*ability to convert error numerical codes to English text string*/
+#ifndef LODEPNG_NO_COMPILE_ERROR_TEXT
+#define LODEPNG_COMPILE_ERROR_TEXT
+#endif
+/*compile the C++ version (you can disable the C++ wrapper here even when compiling for C++)*/
+#ifdef __cplusplus
+#ifndef LODEPNG_NO_COMPILE_CPP
+#define LODEPNG_COMPILE_CPP
+#endif
+#endif
+
+/*
+custom zlib decoder (if LODEPNG_COMPILE_ZLIB is disabled, this is ignored, always treated as "1"):
+0: not custom, use LodePNG's zlib decoder
+1: allow using custom zlib decoder with a setting
+--> you must then provide following function in your source files that LodePNG will link to:
+ unsigned lodepng_custom_inflate(unsigned char**, size_t*, const unsigned char*, size_t,
+ const LodePNGDecompressSettings*)
+2: allow using custom deflate decoder with a setting
+--> you must then provide following function in your source files that LodePNG will link to:
+ unsigned lodepng_custom_zlib_decompress(unsigned char**, size_t*, const unsigned char*, size_t,
+ const LodePNGDecompressSettings*)
+*/
+#ifndef LODEPNG_OVERRIDE_CUSTOM_ZLIB_DECODER
+#define LODEPNG_CUSTOM_ZLIB_DECODER 0
+#else
+#define LODEPNG_CUSTOM_ZLIB_DECODER LODEPNG_OVERRIDE_CUSTOM_ZLIB_DECODER
+#endif
+
+/*
+custom zlib encoder (if LODEPNG_COMPILE_ZLIB is disabled, this is ignored, always treated as "1"):
+0: not custom, use LodePNG's zlib encoder
+1: allow using custom zlib encoder with a setting
+--> you must then provide following function in your source files that LodePNG will link to:
+ unsigned lodepng_custom_deflate(unsigned char**, size_t*, const unsigned char*, size_t,
+ const LodePNGCompressSettings*)
+2: allow using custom deflate encoder with a setting
+--> you must then provide following function in your source files that LodePNG will link to:
+ unsigned lodepng_custom_zlib_compress(unsigned char**, size_t*, const unsigned char*, size_t,
+ const LodePNGCompressSettings*)
+*/
+#ifndef LODEPNG_OVERRIDE_CUSTOM_ZLIB_ENCODER
+#define LODEPNG_CUSTOM_ZLIB_ENCODER 0
+#else
+#define LODEPNG_CUSTOM_ZLIB_ENCODER LODEPNG_OVERRIDE_CUSTOM_ZLIB_ENCODER
+#endif
+
+#ifdef LODEPNG_COMPILE_PNG
+/*The PNG color types (also used for raw).*/
+typedef enum LodePNGColorType
+{
+ LCT_GREY = 0, /*greyscale: 1,2,4,8,16 bit*/
+ LCT_RGB = 2, /*RGB: 8,16 bit*/
+ LCT_PALETTE = 3, /*palette: 1,2,4,8 bit*/
+ LCT_GREY_ALPHA = 4, /*greyscale with alpha: 8,16 bit*/
+ LCT_RGBA = 6 /*RGB with alpha: 8,16 bit*/
+} LodePNGColorType;
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*
+Converts PNG data in memory to raw pixel data.
+out: Output parameter. Pointer to buffer that will contain the raw pixel data.
+ After decoding, its size is w * h * (bytes per pixel) bytes larger than
+ initially. Bytes per pixel depends on colortype and bitdepth.
+ Must be freed after usage with free(*out).
+w: Output parameter. Pointer to width of pixel data.
+h: Output parameter. Pointer to height of pixel data.
+in: Memory buffer with the PNG file.
+insize: size of the in buffer.
+colortype: the desired color type for the raw output image. See explanation on PNG color types.
+bitdepth: the desired bit depth for the raw output image. See explanation on PNG color types.
+Return value: LodePNG error code (0 means no error).
+*/
+unsigned lodepng_decode_memory(unsigned char** out, unsigned* w, unsigned* h,
+ const unsigned char* in, size_t insize,
+ LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_decode_memory, but always decodes to 32-bit RGBA raw image*/
+unsigned lodepng_decode32(unsigned char** out, unsigned* w, unsigned* h,
+ const unsigned char* in, size_t insize);
+
+/*Same as lodepng_decode_memory, but always decodes to 24-bit RGB raw image*/
+unsigned lodepng_decode24(unsigned char** out, unsigned* w, unsigned* h,
+ const unsigned char* in, size_t insize);
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Load PNG from disk, from file with given name.
+Same as the other decode functions, but instead takes a filename as input.
+*/
+unsigned lodepng_decode_file(unsigned char** out, unsigned* w, unsigned* h,
+ const char* filename,
+ LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_decode_file, but always decodes to 32-bit RGBA raw image.*/
+unsigned lodepng_decode32_file(unsigned char** out, unsigned* w, unsigned* h,
+ const char* filename);
+
+/*Same as lodepng_decode_file, but always decodes to 24-bit RGB raw image.*/
+unsigned lodepng_decode24_file(unsigned char** out, unsigned* w, unsigned* h,
+ const char* filename);
+#endif /*LODEPNG_COMPILE_DISK*/
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*
+Converts raw pixel data into a PNG image in memory. The colortype and bitdepth
+ of the output PNG image cannot be chosen, they are automatically determined
+ by the colortype, bitdepth and content of the input pixel data.
+out: Output parameter. Pointer to buffer that will contain the raw pixel data.
+ Must be freed after usage with free(*out).
+outsize: Output parameter. Pointer to the size in bytes of the out buffer.
+image: The raw pixel data to encode. The size of this buffer should be
+ w * h * (bytes per pixel), bytes per pixel depends on colortype and bitdepth.
+w: width of the raw pixel data in pixels.
+h: height of the raw pixel data in pixels.
+colortype: the color type of the raw input image. See explanation on PNG color types.
+bitdepth: the bit depth of the raw input image. See explanation on PNG color types.
+Return value: LodePNG error code (0 means no error).
+*/
+unsigned lodepng_encode_memory(unsigned char** out, size_t* outsize,
+ const unsigned char* image, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_encode_memory, but always encodes from 32-bit RGBA raw image.*/
+unsigned lodepng_encode32(unsigned char** out, size_t* outsize,
+ const unsigned char* image, unsigned w, unsigned h);
+
+/*Same as lodepng_encode_memory, but always encodes from 24-bit RGB raw image.*/
+unsigned lodepng_encode24(unsigned char** out, size_t* outsize,
+ const unsigned char* image, unsigned w, unsigned h);
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Converts raw pixel data into a PNG file on disk.
+Same as the other encode functions, but instead takes a filename as output.
+NOTE: This overwrites existing files without warning!
+*/
+unsigned lodepng_encode_file(const char* filename,
+ const unsigned char* image, unsigned w, unsigned h,
+ LodePNGColorType colortype, unsigned bitdepth);
+
+/*Same as lodepng_encode_file, but always encodes from 32-bit RGBA raw image.*/
+unsigned lodepng_encode32_file(const char* filename,
+ const unsigned char* image, unsigned w, unsigned h);
+
+/*Same as lodepng_encode_file, but always encodes from 24-bit RGB raw image.*/
+unsigned lodepng_encode24_file(const char* filename,
+ const unsigned char* image, unsigned w, unsigned h);
+#endif /*LODEPNG_COMPILE_DISK*/
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+
+#ifdef LODEPNG_COMPILE_CPP
+namespace lodepng
+{
+#ifdef LODEPNG_COMPILE_DECODER
+/*Same as lodepng_decode_memory, but decodes to an std::vector.*/
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ const unsigned char* in, size_t insize,
+ LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ const std::vector<unsigned char>& in,
+ LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Converts PNG file from disk to raw pixel data in memory.
+Same as the other decode functions, but instead takes a filename as input.
+*/
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ const std::string& filename,
+ LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#endif //LODEPNG_COMPILE_DISK
+#endif //LODEPNG_COMPILE_DECODER
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*Same as lodepng_encode_memory, but encodes to an std::vector.*/
+unsigned encode(std::vector<unsigned char>& out,
+ const unsigned char* in, unsigned w, unsigned h,
+ LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+unsigned encode(std::vector<unsigned char>& out,
+ const std::vector<unsigned char>& in, unsigned w, unsigned h,
+ LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Converts 32-bit RGBA raw pixel data into a PNG file on disk.
+Same as the other encode functions, but instead takes a filename as output.
+NOTE: This overwrites existing files without warning!
+*/
+unsigned encode(const std::string& filename,
+ const unsigned char* in, unsigned w, unsigned h,
+ LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+unsigned encode(const std::string& filename,
+ const std::vector<unsigned char>& in, unsigned w, unsigned h,
+ LodePNGColorType colortype = LCT_RGBA, unsigned bitdepth = 8);
+#endif //LODEPNG_COMPILE_DISK
+#endif //LODEPNG_COMPILE_ENCODER
+} //namespace lodepng
+#endif /*LODEPNG_COMPILE_CPP*/
+#endif /*LODEPNG_COMPILE_PNG*/
+
+#ifdef LODEPNG_COMPILE_ERROR_TEXT
+/*Returns an English description of the numerical error code.*/
+const char* lodepng_error_text(unsigned code);
+#endif /*LODEPNG_COMPILE_ERROR_TEXT*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*Settings for zlib decompression*/
+typedef struct LodePNGDecompressSettings
+{
+ unsigned ignore_adler32; /*if 1, continue and don't give an error message if the Adler32 checksum is corrupted*/
+ unsigned custom_decoder; /*use custom decoder if LODEPNG_CUSTOM_ZLIB_DECODER and LODEPNG_COMPILE_ZLIB are enabled*/
+} LodePNGDecompressSettings;
+
+extern const LodePNGDecompressSettings lodepng_default_decompress_settings;
+void lodepng_decompress_settings_init(LodePNGDecompressSettings* settings);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+/*
+Settings for zlib compression. Tweaking these settings tweaks the balance
+between speed and compression ratio.
+*/
+typedef struct LodePNGCompressSettings /*deflate = compress*/
+{
+ /*LZ77 related settings*/
+ unsigned btype; /*the block type for LZ (0, 1, 2 or 3, see zlib standard). Should be 2 for proper compression.*/
+ unsigned use_lz77; /*whether or not to use LZ77. Should be 1 for proper compression.*/
+ unsigned windowsize; /*the maximum is 32768, higher gives more compression but is slower. Typical value: 2048.*/
+ unsigned custom_encoder; /*use custom encoder if LODEPNG_CUSTOM_ZLIB_DECODER and LODEPNG_COMPILE_ZLIB are enabled*/
+} LodePNGCompressSettings;
+
+#ifdef LODEPNG_COMPILE_ENCODER
+extern const LodePNGCompressSettings lodepng_default_compress_settings;
+void lodepng_compress_settings_init(LodePNGCompressSettings* settings);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+#ifdef LODEPNG_COMPILE_PNG
+/*
+Color mode of an image. Contains all information required to decode the pixel
+bits to RGBA colors. This information is the same as used in the PNG file
+format, and is used both for PNG and raw image data in LodePNG.
+*/
+typedef struct LodePNGColorMode
+{
+ /*header (IHDR)*/
+ LodePNGColorType colortype; /*color type, see PNG standard or documentation further in this header file*/
+ unsigned bitdepth; /*bits per sample, see PNG standard or documentation further in this header file*/
+
+ /*
+ palette (PLTE and tRNS)
+
+ Dynamically allocated with the colors of the palette, including alpha.
+ When encoding a PNG, to store your colors in the palette of the LodePNGColorMode, first use
+ lodepng_palette_clear, then for each color use lodepng_palette_add.
+ If you encode an image without alpha with palette, don't forget to put value 255 in each A byte of the palette.
+
+ When decoding, by default you can ignore this palette, since LodePNG already
+ fills the palette colors in the pixels of the raw RGBA output.
+
+ The palette is only supported for color type 3.
+ */
+ unsigned char* palette; /*palette in RGBARGBA... order*/
+ size_t palettesize; /*palette size in number of colors (amount of bytes is 4 * palettesize)*/
+
+ /*
+ transparent color key (tRNS)
+
+ This color uses the same bit depth as the bitdepth value in this struct, which can be 1-bit to 16-bit.
+ For greyscale PNGs, r, g and b will all 3 be set to the same.
+
+ When decoding, by default you can ignore this information, since LodePNG sets
+ pixels with this key to transparent already in the raw RGBA output.
+
+ The color key is only supported for color types 0 and 2.
+ */
+ unsigned key_defined; /*is a transparent color key given? 0 = false, 1 = true*/
+ unsigned key_r; /*red/greyscale component of color key*/
+ unsigned key_g; /*green component of color key*/
+ unsigned key_b; /*blue component of color key*/
+} LodePNGColorMode;
+
+/*init, cleanup and copy functions to use with this struct*/
+void lodepng_color_mode_init(LodePNGColorMode* info);
+void lodepng_color_mode_cleanup(LodePNGColorMode* info);
+/*return value is error code (0 means no error)*/
+unsigned lodepng_color_mode_copy(LodePNGColorMode* dest, const LodePNGColorMode* source);
+
+void lodepng_palette_clear(LodePNGColorMode* info);
+/*add 1 color to the palette*/
+unsigned lodepng_palette_add(LodePNGColorMode* info,
+ unsigned char r, unsigned char g, unsigned char b, unsigned char a);
+
+/*get the total amount of bits per pixel, based on colortype and bitdepth in the struct*/
+unsigned lodepng_get_bpp(const LodePNGColorMode* info);
+/*get the amount of color channels used, based on colortype in the struct.
+If a palette is used, it counts as 1 channel.*/
+unsigned lodepng_get_channels(const LodePNGColorMode* info);
+/*is it a greyscale type? (only colortype 0 or 4)*/
+unsigned lodepng_is_greyscale_type(const LodePNGColorMode* info);
+/*has it got an alpha channel? (only colortype 2 or 6)*/
+unsigned lodepng_is_alpha_type(const LodePNGColorMode* info);
+/*has it got a palette? (only colortype 3)*/
+unsigned lodepng_is_palette_type(const LodePNGColorMode* info);
+/*only returns true if there is a palette and there is a value in the palette with alpha < 255.
+Loops through the palette to check this.*/
+unsigned lodepng_has_palette_alpha(const LodePNGColorMode* info);
+/*
+Check if the given color info indicates the possibility of having non-opaque pixels in the PNG image.
+Returns true if the image can have translucent or invisible pixels (it still be opaque if it doesn't use such pixels).
+Returns false if the image can only have opaque pixels.
+In detail, it returns true only if it's a color type with alpha, or has a palette with non-opaque values,
+or if "key_defined" is true.
+*/
+unsigned lodepng_can_have_alpha(const LodePNGColorMode* info);
+/*Returns the byte size of a raw image buffer with given width, height and color mode*/
+size_t lodepng_get_raw_size(unsigned w, unsigned h, const LodePNGColorMode* color);
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+/*The information of a Time chunk in PNG.*/
+typedef struct LodePNGTime
+{
+ unsigned year; /*2 bytes used (0-65535)*/
+ unsigned month; /*1-12*/
+ unsigned day; /*1-31*/
+ unsigned hour; /*0-23*/
+ unsigned minute; /*0-59*/
+ unsigned second; /*0-60 (to allow for leap seconds)*/
+} LodePNGTime;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+/*Information about the PNG image, except pixels, width and height.*/
+typedef struct LodePNGInfo
+{
+ /*header (IHDR), palette (PLTE) and transparency (tRNS) chunks*/
+ unsigned compression_method;/*compression method of the original file. Always 0.*/
+ unsigned filter_method; /*filter method of the original file*/
+ unsigned interlace_method; /*interlace method of the original file*/
+ LodePNGColorMode color; /*color type and bits, palette and transparency of the PNG file*/
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ /*
+ suggested background color chunk (bKGD)
+ This color uses the same color mode as the PNG (except alpha channel), which can be 1-bit to 16-bit.
+
+ For greyscale PNGs, r, g and b will all 3 be set to the same. When encoding
+ the encoder writes the red one. For palette PNGs: When decoding, the RGB value
+ will be stored, not a palette index. But when encoding, specify the index of
+ the palette in background_r, the other two are then ignored.
+
+ The decoder does not use this background color to edit the color of pixels.
+ */
+ unsigned background_defined; /*is a suggested background color given?*/
+ unsigned background_r; /*red component of suggested background color*/
+ unsigned background_g; /*green component of suggested background color*/
+ unsigned background_b; /*blue component of suggested background color*/
+
+ /*
+ non-international text chunks (tEXt and zTXt)
+
+ The char** arrays each contain num strings. The actual messages are in
+ text_strings, while text_keys are keywords that give a short description what
+ the actual text represents, e.g. Title, Author, Description, or anything else.
+
+ A keyword is minimum 1 character and maximum 79 characters long. It's
+ discouraged to use a single line length longer than 79 characters for texts.
+
+ Don't allocate these text buffers yourself. Use the init/cleanup functions
+ correctly and use lodepng_add_text and lodepng_clear_text.
+ */
+ size_t text_num; /*the amount of texts in these char** buffers (there may be more texts in itext)*/
+ char** text_keys; /*the keyword of a text chunk (e.g. "Comment")*/
+ char** text_strings; /*the actual text*/
+
+ /*
+ international text chunks (iTXt)
+ Similar to the non-international text chunks, but with additional strings
+ "langtags" and "transkeys".
+ */
+ size_t itext_num; /*the amount of international texts in this PNG*/
+ char** itext_keys; /*the English keyword of the text chunk (e.g. "Comment")*/
+ char** itext_langtags; /*language tag for this text's language, ISO/IEC 646 string, e.g. ISO 639 language tag*/
+ char** itext_transkeys; /*keyword translated to the international language - UTF-8 string*/
+ char** itext_strings; /*the actual international text - UTF-8 string*/
+
+ /*time chunk (tIME)*/
+ unsigned time_defined; /*set to 1 to make the encoder generate a tIME chunk*/
+ LodePNGTime time;
+
+ /*phys chunk (pHYs)*/
+ unsigned phys_defined; /*if 0, there is no pHYs chunk and the values below are undefined, if 1 else there is one*/
+ unsigned phys_x; /*pixels per unit in x direction*/
+ unsigned phys_y; /*pixels per unit in y direction*/
+ unsigned phys_unit; /*may be 0 (unknown unit) or 1 (metre)*/
+
+ /*
+ unknown chunks
+ There are 3 buffers, one for each position in the PNG where unknown chunks can appear
+ each buffer contains all unknown chunks for that position consecutively
+ The 3 buffers are the unknown chunks between certain critical chunks:
+ 0: IHDR-PLTE, 1: PLTE-IDAT, 2: IDAT-IEND
+ Do not allocate or traverse this data yourself. Use the chunk traversing functions declared
+ later, such as lodepng_chunk_next and lodepng_chunk_append, to read/write this struct.
+ */
+ unsigned char* unknown_chunks_data[3];
+ size_t unknown_chunks_size[3]; /*size in bytes of the unknown chunks, given for protection*/
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+} LodePNGInfo;
+
+/*init, cleanup and copy functions to use with this struct*/
+void lodepng_info_init(LodePNGInfo* info);
+void lodepng_info_cleanup(LodePNGInfo* info);
+/*return value is error code (0 means no error)*/
+unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source);
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+void lodepng_clear_text(LodePNGInfo* info); /*use this to clear the texts again after you filled them in*/
+unsigned lodepng_add_text(LodePNGInfo* info, const char* key, const char* str); /*push back both texts at once*/
+
+void lodepng_clear_itext(LodePNGInfo* info); /*use this to clear the itexts again after you filled them in*/
+unsigned lodepng_add_itext(LodePNGInfo* info, const char* key, const char* langtag,
+ const char* transkey, const char* str); /*push back the 4 texts of 1 chunk at once*/
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+
+/*
+Converts raw buffer from one color type to another color type, based on
+LodePNGColorMode structs to describe the input and output color type.
+See the reference manual at the end of this header file to see which color conversions are supported.
+return value = LodePNG error code (0 if all went ok, an error if the conversion isn't supported)
+The out buffer must have size (w * h * bpp + 7) / 8, where bpp is the bits per pixel
+of the output color type (lodepng_get_bpp)
+*/
+unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
+ LodePNGColorMode* mode_out, LodePNGColorMode* mode_in,
+ unsigned w, unsigned h);
+
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*
+Settings for the decoder. This contains settings for the PNG and the Zlib
+decoder, but not the Info settings from the Info structs.
+*/
+typedef struct LodePNGDecoderSettings
+{
+ LodePNGDecompressSettings zlibsettings; /*in here is the setting to ignore Adler32 checksums*/
+
+ unsigned ignore_crc; /*ignore CRC checksums*/
+ unsigned color_convert; /*whether to convert the PNG to the color type you want. Default: yes*/
+
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ unsigned read_text_chunks; /*if false but remember_unknown_chunks is true, they're stored in the unknown chunks*/
+ /*store all bytes from unknown chunks in the LodePNGInfo (off by default, useful for a png editor)*/
+ unsigned remember_unknown_chunks;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+} LodePNGDecoderSettings;
+
+void lodepng_decoder_settings_init(LodePNGDecoderSettings* settings);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*automatically use color type with less bits per pixel if losslessly possible. Default: AUTO*/
+typedef enum LodePNGFilterStrategy
+{
+ LFS_HEURISTIC, /*official PNG heuristic*/
+ LFS_ZERO, /*every filter at zero*/
+ LFS_MINSUM, /*like the official PNG heuristic, but use minimal sum always, including palette and low bitdepth images*/
+ /*
+ Brute-force-search PNG filters by compressing each filter for each scanline.
+ This gives better compression, at the cost of being super slow. Experimental!
+ If you enable this, also set zlibsettings.windowsize to 32768 and choose an
+ optimal color mode for the PNG image for best compression. Default: 0 (false).
+ */
+ LFS_BRUTE_FORCE,
+ LFS_PREDEFINED /*use predefined_filters buffer: you specify the filter type for each scanline*/
+} LodePNGFilterStrategy;
+
+/*automatically use color type with less bits per pixel if losslessly possible. Default: LAC_AUTO*/
+typedef enum LodePNGAutoConvert
+{
+ LAC_NO, /*use color type user requested*/
+ LAC_ALPHA, /*use color type user requested, but if only opaque pixels and RGBA or grey+alpha, use RGB or grey*/
+ LAC_AUTO, /*use PNG color type that can losslessly represent the uncompressed image the smallest possible*/
+ /*
+ like AUTO, but do not choose 1, 2 or 4 bit per pixel types.
+ sometimes a PNG image compresses worse if less than 8 bits per pixels.
+ */
+ LAC_AUTO_NO_NIBBLES
+} LodePNGAutoConvert;
+
+
+/*Settings for the encoder.*/
+typedef struct LodePNGEncoderSettings
+{
+ LodePNGCompressSettings zlibsettings; /*settings for the zlib encoder, such as window size, ...*/
+
+ LodePNGAutoConvert auto_convert; /*how to automatically choose output PNG color type, if at all*/
+
+ LodePNGFilterStrategy filter_strategy;
+
+ /*used if filter_strategy is LFS_PREDEFINED. In that case, this must point to a buffer with
+ the same length as the amount of scanlines in the image, and each value must <= 5. You
+ have to cleanup this buffer, LodePNG will never free it.*/
+ unsigned char* predefined_filters;
+
+ /*force creating a PLTE chunk if colortype is 2 or 6 (= a suggested palette).
+ If colortype is 3, PLTE is _always_ created.*/
+ unsigned force_palette;
+#ifdef LODEPNG_COMPILE_ANCILLARY_CHUNKS
+ /*add LodePNG identifier and version as a text chunk, for debugging*/
+ unsigned add_id;
+ /*encode text chunks as zTXt chunks instead of tEXt chunks, and use compression in iTXt chunks*/
+ unsigned text_compression;
+#endif /*LODEPNG_COMPILE_ANCILLARY_CHUNKS*/
+} LodePNGEncoderSettings;
+
+void lodepng_encoder_settings_init(LodePNGEncoderSettings* settings);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+
+#if defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER)
+/*The settings, state and information for extended encoding and decoding.*/
+typedef struct LodePNGState
+{
+#ifdef LODEPNG_COMPILE_DECODER
+ LodePNGDecoderSettings decoder; /*the decoding settings*/
+#endif /*LODEPNG_COMPILE_DECODER*/
+#ifdef LODEPNG_COMPILE_ENCODER
+ LodePNGEncoderSettings encoder; /*the encoding settings*/
+#endif /*LODEPNG_COMPILE_ENCODER*/
+ LodePNGColorMode info_raw; /*specifies the format in which you would like to get the raw pixel buffer*/
+ LodePNGInfo info_png; /*info of the PNG image obtained after decoding*/
+ unsigned error;
+#ifdef LODEPNG_COMPILE_CPP
+ //For the lodepng::State subclass.
+ virtual ~LodePNGState(){}
+#endif
+} LodePNGState;
+
+/*init, cleanup and copy functions to use with this struct*/
+void lodepng_state_init(LodePNGState* state);
+void lodepng_state_cleanup(LodePNGState* state);
+void lodepng_state_copy(LodePNGState* dest, const LodePNGState* source);
+#endif /* defined(LODEPNG_COMPILE_DECODER) || defined(LODEPNG_COMPILE_ENCODER) */
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*
+Same as lodepng_decode_memory, but uses a LodePNGState to allow custom settings and
+getting much more information about the PNG image and color mode.
+*/
+unsigned lodepng_decode(unsigned char** out, unsigned* w, unsigned* h,
+ LodePNGState* state,
+ const unsigned char* in, size_t insize);
+
+/*
+Read the PNG header, but not the actual data. This returns only the information
+that is in the header chunk of the PNG, such as width, height and color type. The
+information is placed in the info_png field of the LodePNGState.
+*/
+unsigned lodepng_inspect(unsigned* w, unsigned* h,
+ LodePNGState* state,
+ const unsigned char* in, size_t insize);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*This function allocates the out buffer with standard malloc and stores the size in *outsize.*/
+unsigned lodepng_encode(unsigned char** out, size_t* outsize,
+ const unsigned char* image, unsigned w, unsigned h,
+ LodePNGState* state);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+/*
+The lodepng_chunk functions are normally not needed, except to traverse the
+unknown chunks stored in the LodePNGInfo struct, or add new ones to it.
+It also allows traversing the chunks of an encoded PNG file yourself.
+
+PNG standard chunk naming conventions:
+First byte: uppercase = critical, lowercase = ancillary
+Second byte: uppercase = public, lowercase = private
+Third byte: must be uppercase
+Fourth byte: uppercase = unsafe to copy, lowercase = safe to copy
+*/
+
+/*get the length of the data of the chunk. Total chunk length has 12 bytes more.*/
+unsigned lodepng_chunk_length(const unsigned char* chunk);
+
+/*puts the 4-byte type in null terminated string*/
+void lodepng_chunk_type(char type[5], const unsigned char* chunk);
+
+/*check if the type is the given type*/
+unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type);
+
+/*0: it's one of the critical chunk types, 1: it's an ancillary chunk (see PNG standard)*/
+unsigned char lodepng_chunk_ancillary(const unsigned char* chunk);
+
+/*0: public, 1: private (see PNG standard)*/
+unsigned char lodepng_chunk_private(const unsigned char* chunk);
+
+/*0: the chunk is unsafe to copy, 1: the chunk is safe to copy (see PNG standard)*/
+unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk);
+
+/*get pointer to the data of the chunk, where the input points to the header of the chunk*/
+unsigned char* lodepng_chunk_data(unsigned char* chunk);
+const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk);
+
+/*returns 0 if the crc is correct, 1 if it's incorrect (0 for OK as usual!)*/
+unsigned lodepng_chunk_check_crc(const unsigned char* chunk);
+
+/*generates the correct CRC from the data and puts it in the last 4 bytes of the chunk*/
+void lodepng_chunk_generate_crc(unsigned char* chunk);
+
+/*iterate to next chunks. don't use on IEND chunk, as there is no next chunk then*/
+unsigned char* lodepng_chunk_next(unsigned char* chunk);
+const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk);
+
+/*
+Appends chunk to the data in out. The given chunk should already have its chunk header.
+The out variable and outlength are updated to reflect the new reallocated buffer.
+Returns error code (0 if it went ok)
+*/
+unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk);
+
+/*
+Appends new chunk to out. The chunk to append is given by giving its length, type
+and data separately. The type is a 4-letter string.
+The out variable and outlength are updated to reflect the new reallocated buffer.
+Returne error code (0 if it went ok)
+*/
+unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length,
+ const char* type, const unsigned char* data);
+
+
+/*Calculate CRC32 of buffer*/
+unsigned lodepng_crc32(const unsigned char* buf, size_t len);
+#endif /*LODEPNG_COMPILE_PNG*/
+
+
+#ifdef LODEPNG_COMPILE_ZLIB
+/*
+This zlib part can be used independently to zlib compress and decompress a
+buffer. It cannot be used to create gzip files however, and it only supports the
+part of zlib that is required for PNG, it does not support dictionaries.
+*/
+
+#ifdef LODEPNG_COMPILE_DECODER
+/*Inflate a buffer. Inflate is the decompression step of deflate. Out buffer must be freed after use.*/
+unsigned lodepng_inflate(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings* settings);
+
+/*
+Decompresses Zlib data. Reallocates the out buffer and appends the data. The
+data must be according to the zlib specification.
+Either, *out must be NULL and *outsize must be 0, or, *out must be a valid
+buffer and *outsize its size in bytes. out must be freed by user after usage.
+*/
+unsigned lodepng_zlib_decompress(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings* settings);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+/*
+Compresses data with Zlib. Reallocates the out buffer and appends the data.
+Zlib adds a small header and trailer around the deflate data.
+The data is output in the format of the zlib specification.
+Either, *out must be NULL and *outsize must be 0, or, *out must be a valid
+buffer and *outsize its size in bytes. out must be freed by user after usage.
+*/
+unsigned lodepng_zlib_compress(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings* settings);
+
+/*
+Find length-limited Huffman code for given frequencies. This function is in the
+public interface only for tests, it's used internally by lodepng_deflate.
+*/
+unsigned lodepng_huffman_code_lengths(unsigned* lengths, const unsigned* frequencies,
+ size_t numcodes, unsigned maxbitlen);
+
+/*Compress a buffer with deflate. See RFC 1951. Out buffer must be freed after use.*/
+unsigned lodepng_deflate(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings* settings);
+
+#endif /*LODEPNG_COMPILE_ENCODER*/
+#endif /*LODEPNG_COMPILE_ZLIB*/
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Load a file from disk into buffer. The function allocates the out buffer, and
+after usage you should free it.
+out: output parameter, contains pointer to loaded buffer.
+outsize: output parameter, size of the allocated out buffer
+filename: the path to the file to load
+return value: error code (0 means ok)
+*/
+unsigned lodepng_load_file(unsigned char** out, size_t* outsize, const char* filename);
+
+/*
+Save a file from buffer to disk. Warning, if it exists, this function overwrites
+the file without warning!
+buffer: the buffer to write
+buffersize: size of the buffer to write
+filename: the path to the file to save to
+return value: error code (0 means ok)
+*/
+unsigned lodepng_save_file(const unsigned char* buffer, size_t buffersize, const char* filename);
+#endif /*LODEPNG_COMPILE_DISK*/
+
+#ifdef LODEPNG_COMPILE_CPP
+//The LodePNG C++ wrapper uses std::vectors instead of manually allocated memory buffers.
+namespace lodepng
+{
+#ifdef LODEPNG_COMPILE_PNG
+class State : public LodePNGState
+{
+ public:
+ State();
+ State(const State& other);
+ virtual ~State();
+ State& operator=(const State& other);
+};
+
+#ifdef LODEPNG_COMPILE_DECODER
+//Same as other lodepng::decode, but using a State for more settings and information.
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ State& state,
+ const unsigned char* in, size_t insize);
+unsigned decode(std::vector<unsigned char>& out, unsigned& w, unsigned& h,
+ State& state,
+ const std::vector<unsigned char>& in);
+#endif /*LODEPNG_COMPILE_DECODER*/
+
+#ifdef LODEPNG_COMPILE_ENCODER
+//Same as other lodepng::encode, but using a State for more settings and information.
+unsigned encode(std::vector<unsigned char>& out,
+ const unsigned char* in, unsigned w, unsigned h,
+ State& state);
+unsigned encode(std::vector<unsigned char>& out,
+ const std::vector<unsigned char>& in, unsigned w, unsigned h,
+ State& state);
+#endif /*LODEPNG_COMPILE_ENCODER*/
+
+
+#ifdef LODEPNG_COMPILE_DISK
+/*
+Load a file from disk into an std::vector. If the vector is empty, then either
+the file doesn't exist or is an empty file.
+*/
+void load_file(std::vector<unsigned char>& buffer, const std::string& filename);
+
+/*
+Save the binary data in an std::vector to a file on disk. The file is overwritten
+without warning.
+*/
+void save_file(const std::vector<unsigned char>& buffer, const std::string& filename);
+#endif //LODEPNG_COMPILE_DISK
+#endif //LODEPNG_COMPILE_PNG
+
+#ifdef LODEPNG_COMPILE_ZLIB
+#ifdef LODEPNG_COMPILE_DECODER
+//Zlib-decompress an unsigned char buffer
+unsigned decompress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings);
+
+//Zlib-decompress an std::vector
+unsigned decompress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+ const LodePNGDecompressSettings& settings = lodepng_default_decompress_settings);
+#endif //LODEPNG_COMPILE_DECODER
+
+#ifdef LODEPNG_COMPILE_ENCODER
+//Zlib-compress an unsigned char buffer
+unsigned compress(std::vector<unsigned char>& out, const unsigned char* in, size_t insize,
+ const LodePNGCompressSettings& settings = lodepng_default_compress_settings);
+
+//Zlib-compress an std::vector
+unsigned compress(std::vector<unsigned char>& out, const std::vector<unsigned char>& in,
+ const LodePNGCompressSettings& settings = lodepng_default_compress_settings);
+#endif //LODEPNG_COMPILE_ENCODER
+#endif //LODEPNG_COMPILE_ZLIB
+} //namespace lodepng
+#endif /*LODEPNG_COMPILE_CPP*/
+
+/*
+TODO:
+[.] test if there are no memory leaks or security exploits - done a lot but needs to be checked often
+[.] check compatibility with vareous compilers - done but needs to be redone for every newer version
+[X] converting color to 16-bit per channel types
+[ ] read all public PNG chunk types (but never let the color profile and gamma ones touch RGB values)
+[ ] make sure encoder generates no chunks with size > (2^31)-1
+[ ] partial decoding (stream processing)
+[X] let the "isFullyOpaque" function check color keys and transparent palettes too
+[X] better name for the variables "codes", "codesD", "codelengthcodes", "clcl" and "lldl"
+[ ] don't stop decoding on errors like 69, 57, 58 (make warnings)
+[ ] make option to choose if the raw image with non multiple of 8 bits per scanline should have padding bits or not
+[ ] let the C++ wrapper catch exceptions coming from the standard library and return LodePNG error codes
+*/
+
+#endif /*LODEPNG_H inclusion guard*/
+
+/*
+LodePNG Documentation
+---------------------
+
+0. table of contents
+--------------------
+
+ 1. about
+ 1.1. supported features
+ 1.2. features not supported
+ 2. C and C++ version
+ 3. security
+ 4. decoding
+ 5. encoding
+ 6. color conversions
+ 6.1. PNG color types
+ 6.2. color conversions
+ 6.3. padding bits
+ 7. error values
+ 8. chunks and PNG editing
+ 9. compiler support
+ 10. examples
+ 10.1. decoder C++ example
+ 10.2. decoder C example
+ 11. changes
+ 12. contact information
+
+
+1. about
+--------
+
+PNG is a file format to store raster images losslessly with good compression,
+supporting different color types and alpha channel.
+
+LodePNG is a PNG codec according to the Portable Network Graphics (PNG)
+Specification (Second Edition) - W3C Recommendation 10 November 2003.
+
+The specifications used are:
+
+*) Portable Network Graphics (PNG) Specification (Second Edition):
+ http://www.w3.org/TR/2003/REC-PNG-20031110
+*) RFC 1950 ZLIB Compressed Data Format version 3.3:
+ http://www.gzip.org/zlib/rfc-zlib.html
+*) RFC 1951 DEFLATE Compressed Data Format Specification ver 1.3:
+ http://www.gzip.org/zlib/rfc-deflate.html
+
+The most recent version of LodePNG can currently be found at
+http://lodev.org/lodepng/
+
+LodePNG works both in C (ISO C90) and C++, with a C++ wrapper that adds
+extra functionality.
+
+LodePNG exists out of two files:
+-lodepng.h: the header file for both C and C++
+-lodepng.c(pp): give it the name lodepng.c or lodepng.cpp (or .cc) depending on your usage
+
+If you want to start using LodePNG right away without reading this doc, get the
+examples from the LodePNG website to see how to use it in code, or check the
+smaller examples in chapter 13 here.
+
+LodePNG is simple but only supports the basic requirements. To achieve
+simplicity, the following design choices were made: There are no dependencies
+on any external library. There are functions to decode and encode a PNG with
+a single function call, and extended versions of these functions taking a
+LodePNGState struct allowing to specify or get more information. By default
+the colors of the raw image are always RGB or RGBA, no matter what color type
+the PNG file uses. To read and write files, there are simple functions to
+convert the files to/from buffers in memory.
+
+This all makes LodePNG suitable for loading textures in games, demos and small
+programs, ... It's less suitable for full fledged image editors, loading PNGs
+over network (it requires all the image data to be available before decoding can
+begin), life-critical systems, ...
+
+1.1. supported features
+-----------------------
+
+The following features are supported by the decoder:
+
+*) decoding of PNGs with any color type, bit depth and interlace mode, to a 24- or 32-bit color raw image,
+ or the same color type as the PNG
+*) encoding of PNGs, from any raw image to 24- or 32-bit color, or the same color type as the raw image
+*) Adam7 interlace and deinterlace for any color type
+*) loading the image from harddisk or decoding it from a buffer from other sources than harddisk
+*) support for alpha channels, including RGBA color model, translucent palettes and color keying
+*) zlib decompression (inflate)
+*) zlib compression (deflate)
+*) CRC32 and ADLER32 checksums
+*) handling of unknown chunks, allowing making a PNG editor that stores custom and unknown chunks.
+*) the following chunks are supported (generated/interpreted) by both encoder and decoder:
+ IHDR: header information
+ PLTE: color palette
+ IDAT: pixel data
+ IEND: the final chunk
+ tRNS: transparency for palettized images
+ tEXt: textual information
+ zTXt: compressed textual information
+ iTXt: international textual information
+ bKGD: suggested background color
+ pHYs: physical dimensions
+ tIME: modification time
+
+1.2. features not supported
+---------------------------
+
+The following features are _not_ supported:
+
+*) some features needed to make a conformant PNG-Editor might be still missing.
+*) partial loading/stream processing. All data must be available and is processed in one call.
+*) The following public chunks are not supported but treated as unknown chunks by LodePNG
+ cHRM, gAMA, iCCP, sRGB, sBIT, hIST, sPLT
+ Some of these are not supported on purpose: LodePNG wants to provide the RGB values
+ stored in the pixels, not values modified by system dependent gamma or color models.
+
+
+2. C and C++ version
+--------------------
+
+The C version uses buffers allocated with alloc that you need to free()
+yourself. You need to use init and cleanup functions for each struct whenever
+using a struct from the C version to avoid exploits and memory leaks.
+
+The C++ version has extra functions with std::vectors in the interface and the
+lodepng::State class which is a LodePNGState with constructor and destructor.
+
+These files work without modification for both C and C++ compilers because all
+the additional C++ code is in "#ifdef __cplusplus" blocks that make C-compilers
+ignore it, and the C code is made to compile both with strict ISO C90 and C++.
+
+To use the C++ version, you need to rename the source file to lodepng.cpp
+(instead of lodepng.c), and compile it with a C++ compiler.
+
+To use the C version, you need to rename the source file to lodepng.c (instead
+of lodepng.cpp), and compile it with a C compiler.
+
+
+3. Security
+-----------
+
+Even if carefully designed, it's always possible that LodePNG contains possible
+exploits. If you discover one, please let me know, and it will be fixed.
+
+When using LodePNG, care has to be taken with the C version of LodePNG, as well
+as the C-style structs when working with C++. The following conventions are used
+for all C-style structs:
+
+-if a struct has a corresponding init function, always call the init function when making a new one
+-if a struct has a corresponding cleanup function, call it before the struct disappears to avoid memory leaks
+-if a struct has a corresponding copy function, use the copy function instead of "=".
+ The destination must also be inited already.
+
+
+4. Decoding
+-----------
+
+Decoding converts a PNG compressed image to a raw pixel buffer.
+
+Most documentation on using the decoder is at its declarations in the header
+above. For C, simple decoding can be done with functions such as
+lodepng_decode32, and more advanced decoding can be done with the struct
+LodePNGState and lodepng_decode. For C++, all decoding can be done with the
+various lodepng::decode functions, and lodepng::State can be used for advanced
+features.
+
+When using the LodePNGState, it uses the following fields for decoding:
+*) LodePNGInfo info_png: it stores extra information about the PNG (the input) in here
+*) LodePNGColorMode info_raw: here you can say what color mode of the raw image (the output) you want to get
+*) LodePNGDecoderSettings decoder: you can specify a few extra settings for the decoder to use
+
+LodePNGInfo info_png
+--------------------
+
+After decoding, this contains extra information of the PNG image, except the actual
+pixels, width and height because these are already gotten directly from the decoder
+functions.
+
+It contains for example the original color type of the PNG image, text comments,
+suggested background color, etc... More details about the LodePNGInfo struct are
+at its declaration documentation.
+
+LodePNGColorMode info_raw
+-------------------------
+
+When decoding, here you can specify which color type you want
+the resulting raw image to be. If this is different from the colortype of the
+PNG, then the decoder will automatically convert the result. This conversion
+always works, except if you want it to convert a color PNG to greyscale or to
+a palette with missing colors.
+
+By default, 32-bit color is used for the result.
+
+LodePNGDecoderSettings decoder
+------------------------------
+
+The settings can be used to ignore the errors created by invalid CRC and Adler32
+chunks, and to disable the decoding of tEXt chunks.
+
+There's also a setting color_convert, true by default. If false, no conversion
+is done, the resulting data will be as it was in the PNG (after decompression)
+and you'll have to puzzle the colors of the pixels together yourself using the
+color type information in the LodePNGInfo.
+
+
+5. Encoding
+-----------
+
+Encoding converts a raw pixel buffer to a PNG compressed image.
+
+Most documentation on using the encoder is at its declarations in the header
+above. For C, simple encoding can be done with functions such as
+lodepng_encode32, and more advanced decoding can be done with the struct
+LodePNGState and lodepng_encode. For C++, all encoding can be done with the
+various lodepng::encode functions, and lodepng::State can be used for advanced
+features.
+
+Like the decoder, the encoder can also give errors. However it gives less errors
+since the encoder input is trusted, the decoder input (a PNG image that could
+be forged by anyone) is not trusted.
+
+When using the LodePNGState, it uses the following fields for encoding:
+*) LodePNGInfo info_png: here you specify how you want the PNG (the output) to be.
+*) LodePNGColorMode info_raw: here you say what color type of the raw image (the input) has
+*) LodePNGEncoderSettings encoder: you can specify a few settings for the encoder to use
+
+LodePNGInfo info_png
+--------------------
+
+When encoding, you use this the opposite way as when decoding: for encoding,
+you fill in the values you want the PNG to have before encoding. By default it's
+not needed to specify a color type for the PNG since it's automatically chosen,
+but it's possible to choose it yourself given the right settings.
+
+The encoder will not always exactly match the LodePNGInfo struct you give,
+it tries as close as possible. Some things are ignored by the encoder. The
+encoder uses, for example, the following settings from it when applicable:
+colortype and bitdepth, text chunks, time chunk, the color key, the palette, the
+background color, the interlace method, unknown chunks, ...
+
+When encoding to a PNG with colortype 3, the encoder will generate a PLTE chunk.
+If the palette contains any colors for which the alpha channel is not 255 (so
+there are translucent colors in the palette), it'll add a tRNS chunk.
+
+LodePNGColorMode info_raw
+-------------------------
+
+You specify the color type of the raw image that you give to the input here,
+including a possible transparent color key and palette you happen to be using in
+your raw image data.
+
+By default, 32-bit color is assumed, meaning your input has to be in RGBA
+format with 4 bytes (unsigned chars) per pixel.
+
+LodePNGEncoderSettings encoder
+------------------------------
+
+The following settings are supported (some are in sub-structs):
+*) auto_convert: when this option is enabled, the encoder will
+automatically choose the smallest possible color mode (including color key) that
+can encode the colors of all pixels without information loss.
+*) btype: the block type for LZ77. 0 = uncompressed, 1 = fixed huffman tree,
+ 2 = dynamic huffman tree (best compression). Should be 2 for proper
+ compression.
+*) use_lz77: whether or not to use LZ77 for compressed block types. Should be
+ true for proper compression.
+*) windowsize: the window size used by the LZ77 encoder (1 - 32768). Has value
+ 2048 by default, but can be set to 32768 for better, but slow, compression.
+*) force_palette: if colortype is 2 or 6, you can make the encoder write a PLTE
+ chunk if force_palette is true. This can used as suggested palette to convert
+ to by viewers that don't support more than 256 colors (if those still exist)
+*) add_id: add text chunk "Encoder: LodePNG <version>" to the image.
+*) text_compression: default 1. If 1, it'll store texts as zTXt instead of tEXt chunks.
+ zTXt chunks use zlib compression on the text. This gives a smaller result on
+ large texts but a larger result on small texts (such as a single program name).
+ It's all tEXt or all zTXt though, there's no separate setting per text yet.
+
+
+6. color conversions
+--------------------
+
+An important thing to note about LodePNG, is that the color type of the PNG, and
+the color type of the raw image, are completely independent. By default, when
+you decode a PNG, you get the result as a raw image in the color type you want,
+no matter whether the PNG was encoded with a palette, greyscale or RGBA color.
+And if you encode an image, by default LodePNG will automatically choose the PNG
+color type that gives good compression based on the values of colors and amount
+of colors in the image. It can be configured to let you control it instead as
+well, though.
+
+To be able to do this, LodePNG does conversions from one color mode to another.
+It can convert from almost any color type to any other color type, except the
+following conversions: RGB to greyscale is not supported, and converting to a
+palette when the palette doesn't have a required color is not supported. This is
+not supported on purpose: this is information loss which requires a color
+reduction algorithm that is beyong the scope of a PNG encoder (yes, RGB to grey
+is easy, but there are multiple ways if you want to give some channels more
+weight).
+
+By default, when decoding, you get the raw image in 32-bit RGBA or 24-bit RGB
+color, no matter what color type the PNG has. And by default when encoding,
+LodePNG automatically picks the best color model for the output PNG, and expects
+the input image to be 32-bit RGBA or 24-bit RGB. So, unless you want to control
+the color format of the images yourself, you can skip this chapter.
+
+6.1. PNG color types
+--------------------
+
+A PNG image can have many color types, ranging from 1-bit color to 64-bit color,
+as well as palettized color modes. After the zlib decompression and unfiltering
+in the PNG image is done, the raw pixel data will have that color type and thus
+a certain amount of bits per pixel. If you want the output raw image after
+decoding to have another color type, a conversion is done by LodePNG.
+
+The PNG specification gives the following color types:
+
+0: greyscale, bit depths 1, 2, 4, 8, 16
+2: RGB, bit depths 8 and 16
+3: palette, bit depths 1, 2, 4 and 8
+4: greyscale with alpha, bit depths 8 and 16
+6: RGBA, bit depths 8 and 16
+
+Bit depth is the amount of bits per pixel per color channel. So the total amount
+of bits per pixel is: amount of channels * bitdepth.
+
+6.2. color conversions
+----------------------
+
+As explained in the sections about the encoder and decoder, you can specify
+color types and bit depths in info_png and info_raw to change the default
+behaviour.
+
+If, when decoding, you want the raw image to be something else than the default,
+you need to set the color type and bit depth you want in the LodePNGColorMode,
+or the parameters of the simple function of LodePNG you're using.
+
+If, when encoding, you use another color type than the default in the input
+image, you need to specify its color type and bit depth in the LodePNGColorMode
+of the raw image, or use the parameters of the simplefunction of LodePNG you're
+using.
+
+If, when encoding, you don't want LodePNG to choose the output PNG color type
+but control it yourself, you need to set auto_convert in the encoder settings
+to LAC_NONE, and specify the color type you want in the LodePNGInfo of the
+encoder.
+
+If you do any of the above, LodePNG may need to do a color conversion, which
+follows the rules below, and may sometimes not be allowed.
+
+To avoid some confusion:
+-the decoder converts from PNG to raw image
+-the encoder converts from raw image to PNG
+-the colortype and bitdepth in LodePNGColorMode info_raw, are those of the raw image
+-the colortype and bitdepth in the color field of LodePNGInfo info_png, are those of the PNG
+-when encoding, the color type in LodePNGInfo is ignored if auto_convert
+ is enabled, it is automatically generated instead
+-when decoding, the color type in LodePNGInfo is set by the decoder to that of the original
+ PNG image, but it can be ignored since the raw image has the color type you requested instead
+-if the color type of the LodePNGColorMode and PNG image aren't the same, a conversion
+ between the color types is done if the color types are supported. If it is not
+ supported, an error is returned. If the types are the same, no conversion is done.
+-even though some conversions aren't supported, LodePNG supports loading PNGs from any
+ colortype and saving PNGs to any colortype, sometimes it just requires preparing
+ the raw image correctly before encoding.
+-both encoder and decoder use the same color converter.
+
+Non supported color conversions:
+-color to greyscale: no error is thrown, but the result will look ugly because
+only the red channel is taken
+-anything, to palette when that palette does not have that color in it: in this
+case an error is thrown
+
+Supported color conversions:
+-anything to 8-bit RGB, 8-bit RGBA, 16-bit RGB, 16-bit RGBA
+-any grey or grey+alpha, to grey or grey+alpha
+-anything to a palette, as long as the palette has the requested colors in it
+-removing alpha channel
+-higher to smaller bitdepth, and vice versa
+
+If you want no color conversion to be done:
+-In the encoder, you can make it save a PNG with any color type by giving the
+raw color mode and LodePNGInfo the same color mode, and setting auto_convert to
+LAC_NO.
+-In the decoder, you can make it store the pixel data in the same color type
+as the PNG has, by setting the color_convert setting to false. Settings in
+info_raw are then ignored.
+
+The function lodepng_convert does the color conversion. It is available in the
+interface but normally isn't needed since the encoder and decoder already call
+it.
+
+6.3. padding bits
+-----------------
+
+In the PNG file format, if a less than 8-bit per pixel color type is used and the scanlines
+have a bit amount that isn't a multiple of 8, then padding bits are used so that each
+scanline starts at a fresh byte. But that is NOT true for the LodePNG raw input and output.
+The raw input image you give to the encoder, and the raw output image you get from the decoder
+will NOT have these padding bits, e.g. in the case of a 1-bit image with a width
+of 7 pixels, the first pixel of the second scanline will the the 8th bit of the first byte,
+not the first bit of a new byte.
+
+
+7. error values
+---------------
+
+All functions in LodePNG that return an error code, return 0 if everything went
+OK, or a non-zero code if there was an error.
+
+The meaning of the LodePNG error values can be retrieved with the function
+lodepng_error_text: given the numerical error code, it returns a description
+of the error in English as a string.
+
+Check the implementation of lodepng_error_text to see the meaning of each code.
+
+
+8. chunks and PNG editing
+-------------------------
+
+If you want to add extra chunks to a PNG you encode, or use LodePNG for a PNG
+editor that should follow the rules about handling of unknown chunks, or if your
+program is able to read other types of chunks than the ones handled by LodePNG,
+then that's possible with the chunk functions of LodePNG.
+
+A PNG chunk has the following layout:
+
+4 bytes length
+4 bytes type name
+length bytes data
+4 bytes CRC
+
+8.1. iterating through chunks
+-----------------------------
+
+If you have a buffer containing the PNG image data, then the first chunk (the
+IHDR chunk) starts at byte number 8 of that buffer. The first 8 bytes are the
+signature of the PNG and are not part of a chunk. But if you start at byte 8
+then you have a chunk, and can check the following things of it.
+
+NOTE: none of these functions check for memory buffer boundaries. To avoid
+exploits, always make sure the buffer contains all the data of the chunks.
+When using lodepng_chunk_next, make sure the returned value is within the
+allocated memory.
+
+unsigned lodepng_chunk_length(const unsigned char* chunk):
+
+Get the length of the chunk's data. The total chunk length is this length + 12.
+
+void lodepng_chunk_type(char type[5], const unsigned char* chunk):
+unsigned char lodepng_chunk_type_equals(const unsigned char* chunk, const char* type):
+
+Get the type of the chunk or compare if it's a certain type
+
+unsigned char lodepng_chunk_critical(const unsigned char* chunk):
+unsigned char lodepng_chunk_private(const unsigned char* chunk):
+unsigned char lodepng_chunk_safetocopy(const unsigned char* chunk):
+
+Check if the chunk is critical in the PNG standard (only IHDR, PLTE, IDAT and IEND are).
+Check if the chunk is private (public chunks are part of the standard, private ones not).
+Check if the chunk is safe to copy. If it's not, then, when modifying data in a critical
+chunk, unsafe to copy chunks of the old image may NOT be saved in the new one if your
+program doesn't handle that type of unknown chunk.
+
+unsigned char* lodepng_chunk_data(unsigned char* chunk):
+const unsigned char* lodepng_chunk_data_const(const unsigned char* chunk):
+
+Get a pointer to the start of the data of the chunk.
+
+unsigned lodepng_chunk_check_crc(const unsigned char* chunk):
+void lodepng_chunk_generate_crc(unsigned char* chunk):
+
+Check if the crc is correct or generate a correct one.
+
+unsigned char* lodepng_chunk_next(unsigned char* chunk):
+const unsigned char* lodepng_chunk_next_const(const unsigned char* chunk):
+
+Iterate to the next chunk. This works if you have a buffer with consecutive chunks. Note that these
+functions do no boundary checking of the allocated data whatsoever, so make sure there is enough
+data available in the buffer to be able to go to the next chunk.
+
+unsigned lodepng_chunk_append(unsigned char** out, size_t* outlength, const unsigned char* chunk):
+unsigned lodepng_chunk_create(unsigned char** out, size_t* outlength, unsigned length,
+ const char* type, const unsigned char* data):
+
+These functions are used to create new chunks that are appended to the data in *out that has
+length *outlength. The append function appends an existing chunk to the new data. The create
+function creates a new chunk with the given parameters and appends it. Type is the 4-letter
+name of the chunk.
+
+8.2. chunks in info_png
+-----------------------
+
+The LodePNGInfo struct contains fields with the unknown chunk in it. It has 3
+buffers (each with size) to contain 3 types of unknown chunks:
+the ones that come before the PLTE chunk, the ones that come between the PLTE
+and the IDAT chunks, and the ones that come after the IDAT chunks.
+It's necessary to make the distionction between these 3 cases because the PNG
+standard forces to keep the ordering of unknown chunks compared to the critical
+chunks, but does not force any other ordering rules.
+
+info_png.unknown_chunks_data[0] is the chunks before PLTE
+info_png.unknown_chunks_data[1] is the chunks after PLTE, before IDAT
+info_png.unknown_chunks_data[2] is the chunks after IDAT
+
+The chunks in these 3 buffers can be iterated through and read by using the same
+way described in the previous subchapter.
+
+When using the decoder to decode a PNG, you can make it store all unknown chunks
+if you set the option settings.remember_unknown_chunks to 1. By default, this
+option is off (0).
+
+The encoder will always encode unknown chunks that are stored in the info_png.
+If you need it to add a particular chunk that isn't known by LodePNG, you can
+use lodepng_chunk_append or lodepng_chunk_create to the chunk data in
+info_png.unknown_chunks_data[x].
+
+Chunks that are known by LodePNG should not be added in that way. E.g. to make
+LodePNG add a bKGD chunk, set background_defined to true and add the correct
+parameters there instead.
+
+
+9. compiler support
+-------------------
+
+No libraries other than the current standard C library are needed to compile
+LodePNG. For the C++ version, only the standard C++ library is needed on top.
+Add the files lodepng.c(pp) and lodepng.h to your project, include
+lodepng.h where needed, and your program can read/write PNG files.
+
+If performance is important, use optimization when compiling! For both the
+encoder and decoder, this makes a large difference.
+
+Make sure that LodePNG is compiled with the same compiler of the same version
+and with the same settings as the rest of the program, or the interfaces with
+std::vectors and std::strings in C++ can be incompatible.
+
+CHAR_BITS must be 8 or higher, because LodePNG uses unsigned chars for octets.
+
+*) gcc and g++
+
+LodePNG is developed in gcc so this compiler is natively supported. It gives no
+warnings with compiler options "-Wall -Wextra -pedantic -ansi", with gcc and g++
+version 4.7.0 on Linux.
+
+*) Mingw
+
+The Mingw compiler (a port of gcc) for Windows is fully supported by LodePNG.
+
+*) Visual Studio 2005 and Visual C++ 2005 Express Edition
+
+Versions 20070604 up to 20080107 have been tested on VS2005 and work. Visual
+studio may give warnings about 'fopen' being deprecated. A multiplatform library
+can't support the proposed Visual Studio alternative however.
+
+If you're using LodePNG in VS2005 and don't want to see the deprecated warnings,
+put this on top of lodepng.h before the inclusions:
+#define _CRT_SECURE_NO_DEPRECATE
+
+Visual Studio may want "stdafx.h" files to be included in each source file. That
+is not standard C++ and will not be added to the stock LodePNG. Try to find a
+setting to disable it for this source file.
+
+*) Visual Studio 6.0
+
+LodePNG support for Visual Studio 6.0 is not guaranteed because VS6 doesn't
+follow the C++ standard correctly.
+
+*) Comeau C/C++
+
+Vesion 20070107 compiles without problems on the Comeau C/C++ Online Test Drive
+at http://www.comeaucomputing.com/tryitout in both C90 and C++ mode.
+
+*) Compilers on Macintosh
+
+LodePNG has been reported to work both with the gcc and LLVM for Macintosh, both
+for C and C++.
+
+*) Other Compilers
+
+If you encounter problems on other compilers, feel free to let me know and I may
+try to fix it if the compiler is modern standards complient.
+
+
+10. examples
+------------
+
+This decoder example shows the most basic usage of LodePNG. More complex
+examples can be found on the LodePNG website.
+
+10.1. decoder C++ example
+-------------------------
+
+#include "lodepng.h"
+#include <iostream>
+
+int main(int argc, char *argv[])
+{
+ const char* filename = argc > 1 ? argv[1] : "test.png";
+
+ //load and decode
+ std::vector<unsigned char> image;
+ unsigned width, height;
+ unsigned error = lodepng::decode(image, width, height, filename);
+
+ //if there's an error, display it
+ if(error) std::cout << "decoder error " << error << ": " << lodepng_error_text(error) << std::endl;
+
+ //the pixels are now in the vector "image", 4 bytes per pixel, ordered RGBARGBA..., use it as texture, draw it, ...
+}
+
+10.2. decoder C example
+-----------------------
+
+#include "lodepng.h"
+
+int main(int argc, char *argv[])
+{
+ unsigned error;
+ unsigned char* image;
+ size_t width, height;
+ const char* filename = argc > 1 ? argv[1] : "test.png";
+
+ error = lodepng_decode32_file(&image, &width, &height, filename);
+
+ if(error) printf("decoder error %u: %s\n", error, lodepng_error_text(error));
+
+ / * use image here * /
+
+ free(image);
+ return 0;
+}
+
+
+11. changes
+-----------
+
+The version number of LodePNG is the date of the change given in the format
+yyyymmdd.
+
+Some changes aren't backwards compatible. Those are indicated with a (!)
+symbol.
+
+*) 23 jun 2012: Added more filter strategies. Made it easier to use custom alloc
+ and free functions and toggle #defines from compiler flags. Small fixes.
+*) 6 may 2012 (!): Made plugging in custom zlib/deflate functions more flexible.
+*) 22 apr 2012 (!): Made interface more consistent, renaming a lot. Removed
+ redundant C++ codec classes. Reduced amount of structs. Everything changed,
+ but it is cleaner now imho and functionality remains the same. Also fixed
+ several bugs and shrinked the implementation code. Made new samples.
+*) 6 nov 2011 (!): By default, the encoder now automatically chooses the best
+ PNG color model and bit depth, based on the amount and type of colors of the
+ raw image. For this, autoLeaveOutAlphaChannel replaced by auto_choose_color.
+*) 9 okt 2011: simpler hash chain implementation for the encoder.
+*) 8 sep 2011: lz77 encoder lazy matching instead of greedy matching.
+*) 23 aug 2011: tweaked the zlib compression parameters after benchmarking.
+ A bug with the PNG filtertype heuristic was fixed, so that it chooses much
+ better ones (it's quite significant). A setting to do an experimental, slow,
+ brute force search for PNG filter types is added.
+*) 17 aug 2011 (!): changed some C zlib related function names.
+*) 16 aug 2011: made the code less wide (max 120 characters per line).
+*) 17 apr 2011: code cleanup. Bugfixes. Convert low to 16-bit per sample colors.
+*) 21 feb 2011: fixed compiling for C90. Fixed compiling with sections disabled.
+*) 11 dec 2010: encoding is made faster, based on suggestion by Peter Eastman
+ to optimize long sequences of zeros.
+*) 13 nov 2010: added LodePNG_InfoColor_hasPaletteAlpha and
+ LodePNG_InfoColor_canHaveAlpha functions for convenience.
+*) 7 nov 2010: added LodePNG_error_text function to get error code description.
+*) 30 okt 2010: made decoding slightly faster
+*) 26 okt 2010: (!) changed some C function and struct names (more consistent).
+ Reorganized the documentation and the declaration order in the header.
+*) 08 aug 2010: only changed some comments and external samples.
+*) 05 jul 2010: fixed bug thanks to warnings in the new gcc version.
+*) 14 mar 2010: fixed bug where too much memory was allocated for char buffers.
+*) 02 sep 2008: fixed bug where it could create empty tree that linux apps could
+ read by ignoring the problem but windows apps couldn't.
+*) 06 jun 2008: added more error checks for out of memory cases.
+*) 26 apr 2008: added a few more checks here and there to ensure more safety.
+*) 06 mar 2008: crash with encoding of strings fixed
+*) 02 feb 2008: support for international text chunks added (iTXt)
+*) 23 jan 2008: small cleanups, and #defines to divide code in sections
+*) 20 jan 2008: support for unknown chunks allowing using LodePNG for an editor.
+*) 18 jan 2008: support for tIME and pHYs chunks added to encoder and decoder.
+*) 17 jan 2008: ability to encode and decode compressed zTXt chunks added
+ Also vareous fixes, such as in the deflate and the padding bits code.
+*) 13 jan 2008: Added ability to encode Adam7-interlaced images. Improved
+ filtering code of encoder.
+*) 07 jan 2008: (!) changed LodePNG to use ISO C90 instead of C++. A
+ C++ wrapper around this provides an interface almost identical to before.
+ Having LodePNG be pure ISO C90 makes it more portable. The C and C++ code
+ are together in these files but it works both for C and C++ compilers.
+*) 29 dec 2007: (!) changed most integer types to unsigned int + other tweaks
+*) 30 aug 2007: bug fixed which makes this Borland C++ compatible
+*) 09 aug 2007: some VS2005 warnings removed again
+*) 21 jul 2007: deflate code placed in new namespace separate from zlib code
+*) 08 jun 2007: fixed bug with 2- and 4-bit color, and small interlaced images
+*) 04 jun 2007: improved support for Visual Studio 2005: crash with accessing
+ invalid std::vector element [0] fixed, and level 3 and 4 warnings removed
+*) 02 jun 2007: made the encoder add a tag with version by default
+*) 27 may 2007: zlib and png code separated (but still in the same file),
+ simple encoder/decoder functions added for more simple usage cases
+*) 19 may 2007: minor fixes, some code cleaning, new error added (error 69),
+ moved some examples from here to lodepng_examples.cpp
+*) 12 may 2007: palette decoding bug fixed
+*) 24 apr 2007: changed the license from BSD to the zlib license
+*) 11 mar 2007: very simple addition: ability to encode bKGD chunks.
+*) 04 mar 2007: (!) tEXt chunk related fixes, and support for encoding
+ palettized PNG images. Plus little interface change with palette and texts.
+*) 03 mar 2007: Made it encode dynamic Huffman shorter with repeat codes.
+ Fixed a bug where the end code of a block had length 0 in the Huffman tree.
+*) 26 feb 2007: Huffman compression with dynamic trees (BTYPE 2) now implemented
+ and supported by the encoder, resulting in smaller PNGs at the output.
+*) 27 jan 2007: Made the Adler-32 test faster so that a timewaste is gone.
+*) 24 jan 2007: gave encoder an error interface. Added color conversion from any
+ greyscale type to 8-bit greyscale with or without alpha.
+*) 21 jan 2007: (!) Totally changed the interface. It allows more color types
+ to convert to and is more uniform. See the manual for how it works now.
+*) 07 jan 2007: Some cleanup & fixes, and a few changes over the last days:
+ encode/decode custom tEXt chunks, separate classes for zlib & deflate, and
+ at last made the decoder give errors for incorrect Adler32 or Crc.
+*) 01 jan 2007: Fixed bug with encoding PNGs with less than 8 bits per channel.
+*) 29 dec 2006: Added support for encoding images without alpha channel, and
+ cleaned out code as well as making certain parts faster.
+*) 28 dec 2006: Added "Settings" to the encoder.
+*) 26 dec 2006: The encoder now does LZ77 encoding and produces much smaller files now.
+ Removed some code duplication in the decoder. Fixed little bug in an example.
+*) 09 dec 2006: (!) Placed output parameters of public functions as first parameter.
+ Fixed a bug of the decoder with 16-bit per color.
+*) 15 okt 2006: Changed documentation structure
+*) 09 okt 2006: Encoder class added. It encodes a valid PNG image from the
+ given image buffer, however for now it's not compressed.
+*) 08 sep 2006: (!) Changed to interface with a Decoder class
+*) 30 jul 2006: (!) LodePNG_InfoPng , width and height are now retrieved in different
+ way. Renamed decodePNG to decodePNGGeneric.
+*) 29 jul 2006: (!) Changed the interface: image info is now returned as a
+ struct of type LodePNG::LodePNG_Info, instead of a vector, which was a bit clumsy.
+*) 28 jul 2006: Cleaned the code and added new error checks.
+ Corrected terminology "deflate" into "inflate".
+*) 23 jun 2006: Added SDL example in the documentation in the header, this
+ example allows easy debugging by displaying the PNG and its transparency.
+*) 22 jun 2006: (!) Changed way to obtain error value. Added
+ loadFile function for convenience. Made decodePNG32 faster.
+*) 21 jun 2006: (!) Changed type of info vector to unsigned.
+ Changed position of palette in info vector. Fixed an important bug that
+ happened on PNGs with an uncompressed block.
+*) 16 jun 2006: Internally changed unsigned into unsigned where
+ needed, and performed some optimizations.
+*) 07 jun 2006: (!) Renamed functions to decodePNG and placed them
+ in LodePNG namespace. Changed the order of the parameters. Rewrote the
+ documentation in the header. Renamed files to lodepng.cpp and lodepng.h
+*) 22 apr 2006: Optimized and improved some code
+*) 07 sep 2005: (!) Changed to std::vector interface
+*) 12 aug 2005: Initial release (C++, decoder only)
+
+
+12. contact information
+-----------------------
+
+Feel free to contact me with suggestions, problems, comments, ... concerning
+LodePNG. If you encounter a PNG image that doesn't work properly with this
+decoder, feel free to send it and I'll use it to find and fix the problem.
+
+My email address is (puzzle the account and domain together with an @ symbol):
+Domain: gmail dot com.
+Account: lode dot vandevenne.
+
+
+Copyright (c) 2005-2012 Lode Vandevenne
+*/
diff --git a/lib/picopng.c b/lib/picopng.c
new file mode 100644
index 0000000000..77cd81cbad
--- /dev/null
+++ b/lib/picopng.c
@@ -0,0 +1,810 @@
+// picoPNG version 20080503 (cleaned up and ported to c by kaitek)
+// Copyright (c) 2005-2008 Lode Vandevenne
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+#include <common.h>
+#include <malloc.h>
+#include "picopng.h"
+
+/*************************************************************************************************/
+
+typedef struct png_alloc_node {
+ struct png_alloc_node *prev, *next;
+ void *addr;
+ size_t size;
+} png_alloc_node_t;
+
+png_alloc_node_t *png_alloc_head = NULL;
+png_alloc_node_t *png_alloc_tail = NULL;
+
+png_alloc_node_t *png_alloc_find_node(void *addr)
+{
+ png_alloc_node_t *node;
+ for (node = png_alloc_head; node; node = node->next)
+ if (node->addr == addr)
+ break;
+ return node;
+}
+
+void png_alloc_add_node(void *addr, size_t size)
+{
+ png_alloc_node_t *node;
+ if (png_alloc_find_node(addr))
+ return;
+ node = malloc(sizeof (png_alloc_node_t));
+ node->addr = addr;
+ node->size = size;
+ node->prev = png_alloc_tail;
+ node->next = NULL;
+ png_alloc_tail = node;
+ if (node->prev)
+ node->prev->next = node;
+ if (!png_alloc_head)
+ png_alloc_head = node;
+}
+
+void png_alloc_remove_node(png_alloc_node_t *node)
+{
+ if (node->prev)
+ node->prev->next = node->next;
+ if (node->next)
+ node->next->prev = node->prev;
+ if (node == png_alloc_head)
+ png_alloc_head = node->next;
+ if (node == png_alloc_tail)
+ png_alloc_tail = node->prev;
+ node->prev = node->next = node->addr = NULL;
+ free(node);
+}
+
+void *png_alloc_malloc(size_t size)
+{
+ void *addr = malloc(size);
+ png_alloc_add_node(addr, size);
+ return addr;
+}
+
+void *png_alloc_realloc(void *addr, size_t size)
+{
+ void *new_addr;
+ if (!addr)
+ return png_alloc_malloc(size);
+ new_addr = realloc(addr, size);
+ if (new_addr != addr) {
+ png_alloc_node_t *old_node;
+ old_node = png_alloc_find_node(addr);
+ png_alloc_remove_node(old_node);
+ png_alloc_add_node(new_addr, size);
+ }
+ return new_addr;
+}
+
+void png_alloc_free(void *addr)
+{
+ png_alloc_node_t *node = png_alloc_find_node(addr);
+ if (!node)
+ return;
+ png_alloc_remove_node(node);
+ free(addr);
+}
+
+void png_alloc_free_all()
+{
+ while (png_alloc_tail) {
+ void *addr = png_alloc_tail->addr;
+ png_alloc_remove_node(png_alloc_tail);
+ free(addr);
+ }
+}
+
+/*************************************************************************************************/
+
+__maybe_unused void vector32_cleanup(vector32_t *p)
+{
+ p->size = p->allocsize = 0;
+ if (p->data)
+ png_alloc_free(p->data);
+ p->data = NULL;
+}
+
+uint32_t vector32_resize(vector32_t *p, size_t size)
+{ // returns 1 if success, 0 if failure ==> nothing done
+ if (size * sizeof (uint32_t) > p->allocsize) {
+ size_t newsize = size * sizeof (uint32_t) * 2;
+ void *data = png_alloc_realloc(p->data, newsize);
+ if (data) {
+ p->allocsize = newsize;
+ p->data = (uint32_t *) data;
+ p->size = size;
+ } else
+ return 0;
+ } else
+ p->size = size;
+ return 1;
+}
+
+uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
+{ // resize and give all new elements the value
+ size_t oldsize = p->size, i;
+ if (!vector32_resize(p, size))
+ return 0;
+ for (i = oldsize; i < size; i++)
+ p->data[i] = value;
+ return 1;
+}
+
+void vector32_init(vector32_t *p)
+{
+ p->data = NULL;
+ p->size = p->allocsize = 0;
+}
+
+vector32_t *vector32_new(size_t size, uint32_t value)
+{
+ vector32_t *p = png_alloc_malloc(sizeof (vector32_t));
+ vector32_init(p);
+ if (size && !vector32_resizev(p, size, value))
+ return NULL;
+ return p;
+}
+
+/*************************************************************************************************/
+
+__maybe_unused void vector8_cleanup(vector8_t *p)
+{
+ p->size = p->allocsize = 0;
+ if (p->data)
+ png_alloc_free(p->data);
+ p->data = NULL;
+}
+
+uint32_t vector8_resize(vector8_t *p, size_t size)
+{ // returns 1 if success, 0 if failure ==> nothing done
+ // xxx: the use of sizeof uint32_t here seems like a bug (this descends from the lodepng vector
+ // compatibility functions which do the same). without this there is corruption in certain cases,
+ // so this was probably done to cover up allocation bug(s) in the original picopng code!
+ if (size * sizeof (uint32_t) > p->allocsize) {
+ size_t newsize = size * sizeof (uint32_t) * 2;
+ void *data = png_alloc_realloc(p->data, newsize);
+ if (data) {
+ p->allocsize = newsize;
+ p->data = (uint8_t *) data;
+ p->size = size;
+ } else
+ return 0; // error: not enough memory
+ } else
+ p->size = size;
+ return 1;
+}
+
+uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
+{ // resize and give all new elements the value
+ size_t oldsize = p->size, i;
+ if (!vector8_resize(p, size))
+ return 0;
+ for (i = oldsize; i < size; i++)
+ p->data[i] = value;
+ return 1;
+}
+
+void vector8_init(vector8_t *p)
+{
+ p->data = NULL;
+ p->size = p->allocsize = 0;
+}
+
+vector8_t *vector8_new(size_t size, uint8_t value)
+{
+ vector8_t *p = png_alloc_malloc(sizeof (vector8_t));
+ vector8_init(p);
+ if (size && !vector8_resizev(p, size, value))
+ return NULL;
+ return p;
+}
+
+vector8_t *vector8_copy(vector8_t *p)
+{
+ vector8_t *q = vector8_new(p->size, 0);
+ uint32_t n;
+ for (n = 0; n < q->size; n++)
+ q->data[n] = p->data[n];
+ return q;
+}
+
+/*************************************************************************************************/
+int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
+{
+ return picopng_zlib_decompress(out->data, out->size, in->data, in->size);
+}
+
+/*************************************************************************************************/
+
+#define PNG_SIGNATURE 0x0a1a0a0d474e5089ull
+
+#define CHUNK_IHDR 0x52444849
+#define CHUNK_IDAT 0x54414449
+#define CHUNK_IEND 0x444e4549
+#define CHUNK_PLTE 0x45544c50
+#define CHUNK_tRNS 0x534e5274
+
+int PNG_error;
+
+uint32_t PNG_readBitFromReversedStream(size_t *bitp, const uint8_t *bits)
+{
+ uint32_t result = (bits[*bitp >> 3] >> (7 - (*bitp & 0x7))) & 1;
+ (*bitp)++;
+ return result;
+}
+
+uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint32_t nbits)
+{
+ uint32_t i, result = 0;
+ for (i = nbits - 1; i < nbits; i--)
+ result += ((PNG_readBitFromReversedStream(bitp, bits)) << i);
+ return result;
+}
+
+void PNG_setBitOfReversedStream(size_t *bitp, uint8_t *bits, uint32_t bit)
+{
+ bits[*bitp >> 3] |= (bit << (7 - (*bitp & 0x7)));
+ (*bitp)++;
+}
+
+uint32_t PNG_read32bitInt(const uint8_t *buffer)
+{
+ return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+}
+
+int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a LodePNG error code
+{
+ if ((colorType == 2 || colorType == 4 || colorType == 6)) {
+ if (!(bd == 8 || bd == 16))
+ return 37;
+ else
+ return 0;
+ } else if (colorType == 0) {
+ if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16))
+ return 37;
+ else
+ return 0;
+ } else if (colorType == 3) {
+ if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8))
+ return 37;
+ else
+ return 0;
+ } else
+ return 31; // nonexistent color type
+}
+
+uint32_t PNG_getBpp(const PNG_info_t *info)
+{
+ uint32_t bitDepth, colorType;
+ bitDepth = info->bitDepth;
+ colorType = info->colorType;
+ if (colorType == 2)
+ return (3 * bitDepth);
+ else if (colorType >= 4)
+ return (colorType - 2) * bitDepth;
+ else
+ return bitDepth;
+}
+
+void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
+{ // read the information from the header and store it in the Info
+ if (inlength < 29) {
+ PNG_error = 27; // error: the data length is smaller than the length of the header
+ return;
+ }
+ if (*(uint64_t *) in != PNG_SIGNATURE) {
+ PNG_error = 28; // no PNG signature
+ return;
+ }
+ if (*(uint32_t *) &in[12] != CHUNK_IHDR) {
+ PNG_error = 29; // error: it doesn't start with a IHDR chunk!
+ return;
+ }
+ info->width = PNG_read32bitInt(&in[16]);
+ info->height = PNG_read32bitInt(&in[20]);
+ info->bitDepth = in[24];
+ info->colorType = in[25];
+ info->compressionMethod = in[26];
+ if (in[26] != 0) {
+ PNG_error = 32; // error: only compression method 0 is allowed in the specification
+ return;
+ }
+ info->filterMethod = in[27];
+ if (in[27] != 0) {
+ PNG_error = 33; // error: only filter method 0 is allowed in the specification
+ return;
+ }
+ info->interlaceMethod = in[28];
+ if (in[28] > 1) {
+ PNG_error = 34; // error: only interlace methods 0 and 1 exist in the specification
+ return;
+ }
+ PNG_error = PNG_checkColorValidity(info->colorType, info->bitDepth);
+}
+
+int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filter type 4
+{
+ int p, pa, pb, pc;
+ p = a + b - c;
+ pa = p > a ? (p - a) : (a - p);
+ pb = p > b ? (p - b) : (b - p);
+ pc = p > c ? (p - c) : (c - p);
+ return (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
+}
+
+void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t *precon,
+ size_t bytewidth, uint32_t filterType, size_t length)
+{
+ size_t i;
+ switch (filterType) {
+ case 0:
+ for (i = 0; i < length; i++)
+ recon[i] = scanline[i];
+ break;
+ case 1:
+ for (i = 0; i < bytewidth; i++)
+ recon[i] = scanline[i];
+ for (i = bytewidth; i < length; i++)
+ recon[i] = scanline[i] + recon[i - bytewidth];
+ break;
+ case 2:
+ if (precon)
+ for (i = 0; i < length; i++)
+ recon[i] = scanline[i] + precon[i];
+ else
+ for (i = 0; i < length; i++)
+ recon[i] = scanline[i];
+ break;
+ case 3:
+ if (precon) {
+ for (i = 0; i < bytewidth; i++)
+ recon[i] = scanline[i] + precon[i] / 2;
+ for (i = bytewidth; i < length; i++)
+ recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
+ } else {
+ for (i = 0; i < bytewidth; i++)
+ recon[i] = scanline[i];
+ for (i = bytewidth; i < length; i++)
+ recon[i] = scanline[i] + recon[i - bytewidth] / 2;
+ }
+ break;
+ case 4:
+ if (precon) {
+ for (i = 0; i < bytewidth; i++)
+ recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(0, precon[i], 0));
+ for (i = bytewidth; i < length; i++)
+ recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth],
+ precon[i], precon[i - bytewidth]));
+ } else {
+ for (i = 0; i < bytewidth; i++)
+ recon[i] = scanline[i];
+ for (i = bytewidth; i < length; i++)
+ recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth], 0, 0));
+ }
+ break;
+ default:
+ PNG_error = 36; // error: nonexistent filter type given
+ return;
+ }
+}
+
+void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *in, uint32_t w,
+ size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh,
+ uint32_t bpp)
+{
+ size_t bytewidth, linelength;
+ uint32_t y;
+ uint8_t *temp;
+ // filter and reposition the pixels into the output when the image is Adam7 interlaced. This
+ // function can only do it after the full image is already decoded. The out buffer must have
+ // the correct allocated memory size already.
+ if (passw == 0)
+ return;
+ bytewidth = (bpp + 7) / 8;
+ linelength = 1 + ((bpp * passw + 7) / 8);
+ for (y = 0; y < passh; y++) {
+ size_t i, b;
+ uint8_t filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo;
+ PNG_unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType,
+ (w * bpp + 7) / 8);
+ if (PNG_error)
+ return;
+ if (bpp >= 8)
+ for (i = 0; i < passw; i++)
+ for (b = 0; b < bytewidth; b++) // b = current byte of this pixel
+ out[bytewidth * w * (passtop + spacey * y) + bytewidth *
+ (passleft + spacex * i) + b] = linen[bytewidth * i + b];
+ else
+ for (i = 0; i < passw; i++) {
+ size_t obp, bp;
+ obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i);
+ bp = i * bpp;
+ for (b = 0; b < bpp; b++)
+ PNG_setBitOfReversedStream(&obp, out, PNG_readBitFromReversedStream(&bp, linen));
+ }
+ temp = linen;
+ linen = lineo;
+ lineo = temp; // swap the two buffer pointers "line old" and "line new"
+ }
+}
+
+int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
+{ // converts from any color type to 32-bit. return value = LodePNG error code
+ size_t i, c;
+ uint32_t bitDepth, colorType;
+ size_t numpixels, bp;
+ uint8_t *out_data;
+
+ bitDepth = info->bitDepth;
+ colorType = info->colorType;
+ numpixels = info->width * info->height;
+ bp = 0;
+ vector8_resize(out, numpixels * 4);
+ out_data = out->size ? out->data : 0;
+ if (bitDepth == 8 && colorType == 0) // greyscale
+ for (i = 0; i < numpixels; i++) {
+ out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[i];
+ out_data[4 * i + 3] = (info->key_defined && (in[i] == info->key_r)) ? 0 : 255;
+ }
+ else if (bitDepth == 8 && colorType == 2) // RGB color
+ for (i = 0; i < numpixels; i++) {
+ for (c = 0; c < 3; c++)
+ out_data[4 * i + c] = in[3 * i + c];
+ out_data[4 * i + 3] = (info->key_defined && (in[3 * i + 0] == info->key_r) &&
+ (in[3 * i + 1] == info->key_g) && (in[3 * i + 2] == info->key_b)) ? 0 : 255;
+ }
+ else if (bitDepth == 8 && colorType == 3) // indexed color (palette)
+ for (i = 0; i < numpixels; i++) {
+ if (4U * in[i] >= info->palette->size)
+ return 46;
+ for (c = 0; c < 4; c++) // get rgb colors from the palette
+ out_data[4 * i + c] = info->palette->data[4 * in[i] + c];
+ }
+ else if (bitDepth == 8 && colorType == 4) // greyscale with alpha
+ for (i = 0; i < numpixels; i++) {
+ out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i + 0];
+ out_data[4 * i + 3] = in[2 * i + 1];
+ }
+ else if (bitDepth == 8 && colorType == 6)
+ for (i = 0; i < numpixels; i++)
+ for (c = 0; c < 4; c++)
+ out_data[4 * i + c] = in[4 * i + c]; // RGB with alpha
+ else if (bitDepth == 16 && colorType == 0) // greyscale
+ for (i = 0; i < numpixels; i++) {
+ out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i];
+ out_data[4 * i + 3] = (info->key_defined && (256U * in[i] + in[i + 1] == info->key_r))
+ ? 0 : 255;
+ }
+ else if (bitDepth == 16 && colorType == 2) // RGB color
+ for (i = 0; i < numpixels; i++) {
+ for (c = 0; c < 3; c++)
+ out_data[4 * i + c] = in[6 * i + 2 * c];
+ out_data[4 * i + 3] = (info->key_defined &&
+ (256U * in[6 * i + 0] + in[6 * i + 1] == info->key_r) &&
+ (256U * in[6 * i + 2] + in[6 * i + 3] == info->key_g) &&
+ (256U * in[6 * i + 4] + in[6 * i + 5] == info->key_b)) ? 0 : 255;
+ }
+ else if (bitDepth == 16 && colorType == 4) // greyscale with alpha
+ for (i = 0; i < numpixels; i++) {
+ out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[4 * i]; // msb
+ out_data[4 * i + 3] = in[4 * i + 2];
+ }
+ else if (bitDepth == 16 && colorType == 6)
+ for (i = 0; i < numpixels; i++)
+ for (c = 0; c < 4; c++)
+ out_data[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha
+ else if (bitDepth < 8 && colorType == 0) // greyscale
+ for (i = 0; i < numpixels; i++) {
+ uint32_t value = (PNG_readBitsFromReversedStream(&bp, in, bitDepth) * 255) /
+ ((1 << bitDepth) - 1); // scale value from 0 to 255
+ out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = (uint8_t) value;
+ out_data[4 * i + 3] = (info->key_defined && value &&
+ (((1U << bitDepth) - 1U) == info->key_r) && ((1U << bitDepth) - 1U)) ? 0 : 255;
+ }
+ else if (bitDepth < 8 && colorType == 3) // palette
+ for (i = 0; i < numpixels; i++) {
+ uint32_t value = PNG_readBitsFromReversedStream(&bp, in, bitDepth);
+ if (4 * value >= info->palette->size)
+ return 47;
+ for (c = 0; c < 4; c++) // get rgb colors from the palette
+ out_data[4 * i + c] = info->palette->data[4 * value + c];
+ }
+ return 0;
+}
+
+PNG_info_t *PNG_info_new(void)
+{
+ PNG_info_t *info = png_alloc_malloc(sizeof (PNG_info_t));
+ uint32_t i;
+ for (i = 0; i < sizeof (PNG_info_t); i++)
+ ((uint8_t *) info)[i] = 0;
+ info->palette = vector8_new(0, 0);
+ info->image = vector8_new(0, 0);
+ return info;
+}
+
+PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size)
+{
+ PNG_info_t *info;
+ size_t pos;
+ vector8_t *idat;
+ bool IEND, known_type;
+ uint32_t bpp;
+ vector8_t *scanlines; // now the out buffer will be filled
+ size_t bytewidth, outlength;
+ uint8_t *out_data;
+
+ PNG_error = 0;
+
+ if (size == 0 || in == 0) {
+ PNG_error = 48; // the given data is empty
+ return NULL;
+ }
+ info = PNG_info_new();
+ PNG_readPngHeader(info, in, size);
+ if (PNG_error)
+ return NULL;
+ pos = 33; // first byte of the first chunk after the header
+ idat = NULL; // the data from idat chunks
+ IEND = false;
+ known_type = true;
+ info->key_defined = false;
+ // loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is
+ // put at the start of the in buffer
+ while (!IEND) {
+ size_t i, j;
+ size_t chunkLength;
+ uint32_t chunkType;
+
+ if (pos + 8 >= size) {
+ PNG_error = 30; // error: size of the in buffer too small to contain next chunk
+ return NULL;
+ }
+ chunkLength = PNG_read32bitInt(&in[pos]);
+ pos += 4;
+ if (chunkLength > 0x7fffffff) {
+ PNG_error = 63;
+ return NULL;
+ }
+ if (pos + chunkLength >= size) {
+ PNG_error = 35; // error: size of the in buffer too small to contain next chunk
+ return NULL;
+ }
+ chunkType = *(uint32_t *) &in[pos];
+ if (chunkType == CHUNK_IDAT) { // IDAT: compressed image data chunk
+ size_t offset = 0;
+ if (idat) {
+ offset = idat->size;
+ vector8_resize(idat, offset + chunkLength);
+ } else
+ idat = vector8_new(chunkLength, 0);
+ for (i = 0; i < chunkLength; i++)
+ idat->data[offset + i] = in[pos + 4 + i];
+ pos += (4 + chunkLength);
+ } else if (chunkType == CHUNK_IEND) { // IEND
+ pos += 4;
+ IEND = true;
+ } else if (chunkType == CHUNK_PLTE) { // PLTE: palette chunk
+ pos += 4; // go after the 4 letters
+ vector8_resize(info->palette, 4 * (chunkLength / 3));
+ if (info->palette->size > (4 * 256)) {
+ PNG_error = 38; // error: palette too big
+ return NULL;
+ }
+ for (i = 0; i < info->palette->size; i += 4) {
+ for (j = 0; j < 3; j++)
+ info->palette->data[i + j] = in[pos++]; // RGB
+ info->palette->data[i + 3] = 255; // alpha
+ }
+ } else if (chunkType == CHUNK_tRNS) { // tRNS: palette transparency chunk
+ pos += 4; // go after the 4 letters
+ if (info->colorType == 3) {
+ if (4 * chunkLength > info->palette->size) {
+ PNG_error = 39; // error: more alpha values given than there are palette entries
+ return NULL;
+ }
+ for (i = 0; i < chunkLength; i++)
+ info->palette->data[4 * i + 3] = in[pos++];
+ } else if (info->colorType == 0) {
+ if (chunkLength != 2) {
+ PNG_error = 40; // error: this chunk must be 2 bytes for greyscale image
+ return NULL;
+ }
+ info->key_defined = true;
+ info->key_r = info->key_g = info->key_b = 256 * in[pos] + in[pos + 1];
+ pos += 2;
+ } else if (info->colorType == 2) {
+ if (chunkLength != 6) {
+ PNG_error = 41; // error: this chunk must be 6 bytes for RGB image
+ return NULL;
+ }
+ info->key_defined = true;
+ info->key_r = 256 * in[pos] + in[pos + 1];
+ pos += 2;
+ info->key_g = 256 * in[pos] + in[pos + 1];
+ pos += 2;
+ info->key_b = 256 * in[pos] + in[pos + 1];
+ pos += 2;
+ } else {
+ PNG_error = 42; // error: tRNS chunk not allowed for other color models
+ return NULL;
+ }
+ } else { // it's not an implemented chunk type, so ignore it: skip over the data
+ if (!(in[pos + 0] & 32)) {
+ // error: unknown critical chunk (5th bit of first byte of chunk type is 0)
+ PNG_error = 69;
+ return NULL;
+ }
+ pos += (chunkLength + 4); // skip 4 letters and uninterpreted data of unimplemented chunk
+ known_type = false;
+ }
+ pos += 4; // step over CRC (which is ignored)
+ }
+ bpp = PNG_getBpp(info);
+ scanlines = vector8_new(((info->width * (info->height * bpp + 7)) / 8) + info->height, 0);
+ PNG_error = Zlib_decompress(scanlines, idat);
+ if (PNG_error)
+ return NULL; // stop if the zlib decompressor returned an error
+ bytewidth = (bpp + 7) / 8;
+ outlength = (info->height * info->width * bpp + 7) / 8;
+ vector8_resize(info->image, outlength); // time to fill the out buffer
+ out_data = outlength ? info->image->data : 0;
+ if (info->interlaceMethod == 0) { // no interlace, just filter
+ size_t y, obp, bp;
+ size_t linestart, linelength;
+ linestart = 0;
+ // length in bytes of a scanline, excluding the filtertype byte
+ linelength = (info->width * bpp + 7) / 8;
+ if (bpp >= 8) // byte per byte
+ for (y = 0; y < info->height; y++) {
+ uint32_t filterType = scanlines->data[linestart];
+ const uint8_t *prevline;
+ prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
+ PNG_unFilterScanline(&out_data[linestart - y], &scanlines->data[linestart + 1],
+ prevline, bytewidth, filterType, linelength);
+ if (PNG_error)
+ return NULL;
+ linestart += (1 + linelength); // go to start of next scanline
+ } else { // less than 8 bits per pixel, so fill it up bit per bit
+ vector8_t *templine; // only used if bpp < 8
+ templine = vector8_new((info->width * bpp + 7) >> 3, 0);
+ for (y = 0, obp = 0; y < info->height; y++) {
+ uint32_t filterType = scanlines->data[linestart];
+ const uint8_t *prevline;
+ prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
+ PNG_unFilterScanline(templine->data, &scanlines->data[linestart + 1], prevline,
+ bytewidth, filterType, linelength);
+ if (PNG_error)
+ return NULL;
+ for (bp = 0; bp < info->width * bpp;)
+ PNG_setBitOfReversedStream(&obp, out_data, PNG_readBitFromReversedStream(&bp,
+ templine->data));
+ linestart += (1 + linelength); // go to start of next scanline
+ }
+ }
+ } else { // interlaceMethod is 1 (Adam7)
+ int i;
+ vector8_t *scanlineo, *scanlinen; // "old" and "new" scanline
+ size_t passw[7] = {
+ (info->width + 7) / 8, (info->width + 3) / 8, (info->width + 3) / 4,
+ (info->width + 1) / 4, (info->width + 1) / 2, (info->width + 0) / 2,
+ (info->width + 0) / 1
+ };
+ size_t passh[7] = {
+ (info->height + 7) / 8, (info->height + 7) / 8, (info->height + 3) / 8,
+ (info->height + 3) / 4, (info->height + 1) / 4, (info->height + 1) / 2,
+ (info->height + 0) / 2
+ };
+ size_t passstart[7] = { 0 };
+ size_t pattern[28] = { 0, 4, 0, 2, 0, 1, 0, 0, 0, 4, 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, 1, 8, 8,
+ 8, 4, 4, 2, 2 }; // values for the adam7 passes
+ for (i = 0; i < 6; i++)
+ passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8);
+ scanlineo = vector8_new((info->width * bpp + 7) / 8, 0);
+ scanlinen = vector8_new((info->width * bpp + 7) / 8, 0);
+ for (i = 0; i < 7; i++)
+ PNG_adam7Pass(out_data, scanlinen->data, scanlineo->data, &scanlines->data[passstart[i]],
+ info->width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21],
+ passw[i], passh[i], bpp);
+ }
+ if (info->colorType != 6 || info->bitDepth != 8) { // conversion needed
+ vector8_t *copy = vector8_copy(info->image); // xxx: is this copy necessary?
+ PNG_error = PNG_convert(info, info->image, copy->data);
+ }
+ return info;
+}
+
+/*************************************************************************************************/
+
+#ifdef TEST
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+int main(int argc, char **argv)
+{
+ char *fname = (argc > 1) ? argv[1] : "test.png";
+ PNG_info_t *info;
+ struct stat statbuf;
+ uint32_t insize, outsize;
+ FILE *infp, *outfp;
+ uint8_t *inbuf;
+ uint32_t n;
+
+ if (stat(fname, &statbuf) != 0) {
+ perror("stat");
+ return 1;
+ } else if (!statbuf.st_size) {
+ printf("file empty\n");
+ return 1;
+ }
+ insize = (uint32_t) statbuf.st_size;
+ inbuf = malloc(insize);
+ infp = fopen(fname, "rb");
+ if (!infp) {
+ perror("fopen");
+ return 1;
+ } else if (fread(inbuf, 1, insize, infp) != insize) {
+ perror("fread");
+ return 1;
+ }
+ fclose(infp);
+
+ printf("input file: %s (size: %d)\n", fname, insize);
+
+ info = PNG_decode(inbuf, insize);
+ free(inbuf);
+ printf("PNG_error: %d\n", PNG_error);
+ if (PNG_error != 0)
+ return 1;
+
+ printf("width: %d, height: %d\nfirst 16 bytes: ", info->width, info->height);
+ for (n = 0; n < 16; n++)
+ printf("%02x ", info->image->data[n]);
+ printf("\n");
+
+ outsize = info->width * info->height * 4;
+ printf("image size: %d\n", outsize);
+ if (outsize != info->image->size) {
+ printf("error: image size doesn't match dimensions\n");
+ return 1;
+ }
+ outfp = fopen("out.bin", "wb");
+ if (!outfp) {
+ perror("fopen");
+ return 1;
+ } else if (fwrite(info->image->data, 1, outsize, outfp) != outsize) {
+ perror("fwrite");
+ return 1;
+ }
+ fclose(outfp);
+
+#ifdef ALLOC_DEBUG
+ png_alloc_node_t *node;
+ for (node = png_alloc_head, n = 1; node; node = node->next, n++)
+ printf("node %d (%p) addr = %p, size = %ld\n", n, node, node->addr, node->size);
+#endif
+ png_alloc_free_all(); // also frees info and image data from PNG_decode
+
+ return 0;
+}
+
+#endif
diff --git a/lib/picopng.h b/lib/picopng.h
new file mode 100644
index 0000000000..14c5e28bcc
--- /dev/null
+++ b/lib/picopng.h
@@ -0,0 +1,34 @@
+#ifndef _PICOPNG_H
+#define _PICOPNG_H
+
+typedef struct {
+ uint32_t *data;
+ size_t size;
+ size_t allocsize;
+} vector32_t;
+
+typedef struct {
+ uint8_t *data;
+ size_t size;
+ size_t allocsize;
+} vector8_t;
+
+typedef struct {
+ uint32_t width, height;
+ uint32_t colorType, bitDepth;
+ uint32_t compressionMethod, filterMethod, interlaceMethod;
+ uint32_t key_r, key_g, key_b;
+ bool key_defined; // is a transparent color key given?
+ vector8_t *palette;
+ vector8_t *image;
+} PNG_info_t;
+
+PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size);
+void png_alloc_free_all(void);
+
+unsigned picopng_zlib_decompress(unsigned char* out, size_t outsize,
+ const unsigned char* in, size_t insize);
+
+extern int PNG_error;
+
+#endif
diff --git a/lib/png.c b/lib/png.c
new file mode 100644
index 0000000000..f71fc6abc8
--- /dev/null
+++ b/lib/png.c
@@ -0,0 +1,89 @@
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fb.h>
+#include <asm/byteorder.h>
+#include <init.h>
+#include <image_renderer.h>
+#include <graphic_utils.h>
+#include <linux/zlib.h>
+
+#include "png.h"
+
+z_stream png_stream;
+static int initialized;
+
+int png_uncompress_init(void)
+{
+ if (!initialized++) {
+ png_stream.workspace = malloc(zlib_inflate_workspacesize());
+ if (!png_stream.workspace) {
+ initialized = 0;
+ return -ENOMEM;
+ }
+ png_stream.next_in = NULL;
+ png_stream.avail_in = 0;
+ zlib_inflateInit(&png_stream);
+ }
+ return 0;
+}
+
+void png_uncompress_exit(void)
+{
+ if (!--initialized) {
+ zlib_inflateEnd(&png_stream);
+ vfree(png_stream.workspace);
+ }
+}
+
+static int png_renderer(struct fb_info *info, struct image *img, void* fb,
+ int startx, int starty, void* offscreenbuf)
+{
+ int width, height;
+ void *buf;
+ int xres, yres;
+
+ xres = info->xres;
+ yres = info->yres;
+
+ if (startx < 0) {
+ startx = (xres - img->width) / 2;
+ if (startx < 0)
+ startx = 0;
+ }
+
+ if (starty < 0) {
+ starty = (yres - img->height) / 2;
+ if (starty < 0)
+ starty = 0;
+ }
+
+ width = min(img->width, xres - startx);
+ height = min(img->height, yres - starty);
+
+ buf = offscreenbuf ? offscreenbuf : fb;
+
+ rgba_blend(info, img->data, buf, height, width, startx, starty, true);
+
+ if (offscreenbuf) {
+ int fbsize;
+
+ fbsize = xres * yres * (info->bits_per_pixel >> 3);
+ memcpy(fb, offscreenbuf, fbsize);
+ }
+
+ return img->height;
+}
+
+static struct image_renderer png = {
+ .type = filetype_png,
+ .open = png_open,
+ .close = png_close,
+ .renderer = png_renderer,
+};
+
+static int png_init(void)
+{
+ return image_renderer_register(&png);
+}
+fs_initcall(png_init);
diff --git a/lib/png.h b/lib/png.h
new file mode 100644
index 0000000000..3ac9364d46
--- /dev/null
+++ b/lib/png.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+ *
+ * GPL v2
+ */
+
+#ifndef __PNG_H__
+#define __PNG_H__
+
+#include <filetype.h>
+#include <linux/list.h>
+#include <errno.h>
+#include <linux/err.h>
+
+int png_uncompress_init(void);
+void png_uncompress_exit(void);
+void png_close(struct image *img);
+struct image *png_open(char *inbuf, int insize);
+extern z_stream png_stream;
+
+#endif /* __PNG_H__ */
diff --git a/lib/png_lode.c b/lib/png_lode.c
new file mode 100644
index 0000000000..4b57f6ad20
--- /dev/null
+++ b/lib/png_lode.c
@@ -0,0 +1,90 @@
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fb.h>
+#include <asm/byteorder.h>
+#include <init.h>
+#include <image_renderer.h>
+#include <graphic_utils.h>
+#include <linux/zlib.h>
+
+#include "lodepng.h"
+#include "png.h"
+
+unsigned lodepng_custom_zlib_decompress(unsigned char** out, size_t* outsize,
+ const unsigned char* in, size_t insize,
+ const LodePNGDecompressSettings* settings)
+{
+ int err;
+
+ png_stream.next_in = in;
+ png_stream.avail_in = insize;
+
+ png_stream.next_out = *out;
+ png_stream.avail_out = *outsize;
+
+ err = zlib_inflateReset(&png_stream);
+ if (err != Z_OK) {
+ printk("zlib_inflateReset error %d\n", err);
+ zlib_inflateEnd(&png_stream);
+ zlib_inflateInit(&png_stream);
+ }
+
+ err = zlib_inflate(&png_stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto err;
+ return 0;
+
+err:
+ printk("Error %d while decompressing!\n", err);
+ printk("%p(%zd)->%p(%zd)\n", in, insize, *out, *outsize);
+ return -EIO;
+}
+
+struct image *png_open(char *inbuf, int insize)
+{
+ LodePNGState state;
+ int ret;
+ unsigned error;
+ struct image *img = calloc(1, sizeof(struct image));
+ unsigned char *png;
+
+ if (!img)
+ return ERR_PTR(-ENOMEM);
+
+ ret = png_uncompress_init();
+ if (ret)
+ goto err;
+
+ lodepng_state_init(&state);
+
+ state.info_raw.colortype = LCT_RGBA;
+ state.info_raw.bitdepth = 8;
+
+ error = lodepng_decode(&png, &img->width, &img->height, &state, inbuf, insize);
+
+ if(error) {
+ printf("error %u: %s\n", error, lodepng_error_text(error));
+ ret = -EINVAL;
+ goto err;
+ }
+
+ img->bits_per_pixel = 4 << 3;
+ img->data = png;
+
+ pr_debug("png: %d x %d data@0x%p\n", img->width, img->height, img->data);
+
+ lodepng_state_cleanup(&state);
+
+ return img;
+err:
+ free(png);
+ free(img);
+ return ERR_PTR(ret);
+}
+
+void png_close(struct image *img)
+{
+ free(img->data);
+ png_uncompress_exit();
+}
diff --git a/lib/png_pico.c b/lib/png_pico.c
new file mode 100644
index 0000000000..a0127f7674
--- /dev/null
+++ b/lib/png_pico.c
@@ -0,0 +1,85 @@
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fb.h>
+#include <asm/byteorder.h>
+#include <init.h>
+#include <image_renderer.h>
+#include <graphic_utils.h>
+#include <linux/zlib.h>
+
+#include "picopng.h"
+#include "png.h"
+
+unsigned picopng_zlib_decompress(unsigned char* out, size_t outsize,
+ const unsigned char* in, size_t insize)
+{
+ int err;
+
+ png_stream.next_in = in;
+ png_stream.avail_in = insize;
+
+ png_stream.next_out = out;
+ png_stream.avail_out = outsize;
+
+ err = zlib_inflateReset(&png_stream);
+ if (err != Z_OK) {
+ printk("zlib_inflateReset error %d\n", err);
+ zlib_inflateEnd(&png_stream);
+ zlib_inflateInit(&png_stream);
+ }
+
+ err = zlib_inflate(&png_stream, Z_FINISH);
+ if (err != Z_STREAM_END)
+ goto err;
+ return 0;
+
+err:
+ printk("Error %d while decompressing!\n", err);
+ printk("%p(%zd)->%p(%zd)\n", in, insize, out, outsize);
+ return -EIO;
+}
+
+struct image *png_open(char *inbuf, int insize)
+{
+ PNG_info_t *png_info;
+ int ret;
+ struct image *img = calloc(1, sizeof(struct image));
+
+ if (!img)
+ return ERR_PTR(-ENOMEM);
+
+ ret = png_uncompress_init();
+ if (ret)
+ goto err;
+
+ /* rgba */
+ png_info = PNG_decode(inbuf, insize);
+
+ if(PNG_error) {
+ printf("error %u:\n", PNG_error);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ img->width = png_info->width;
+ img->height = png_info->height;
+ img->bits_per_pixel = 4 << 3;
+ img->data = png_info->image->data;
+
+ pr_debug("png: %d x %d data@0x%p\n", img->width, img->height, img->data);
+
+ png_alloc_free_all();
+
+ return img;
+err:
+ png_alloc_free_all();
+ free(img);
+ return ERR_PTR(ret);
+}
+
+void png_close(struct image *img)
+{
+ free(img->data);
+ png_alloc_free_all();
+}
diff --git a/logo/LICENCE b/logo/LICENCE
new file mode 100644
index 0000000000..91f6c06ef3
--- /dev/null
+++ b/logo/LICENCE
@@ -0,0 +1,22 @@
+Barebox Logo Licence
+
+Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
+Copyright (C) 2012 JCrosoft.Ling Limited
+
+This logo or a modified version may be used by anyone to refer to the Barebox
+project only, but does not indicate endorsement by the project.
+
+The logo can be modified in the limit of the respect of the image to the
+Barebox project.
+
+In particular, we encourage you to use the logo for the purpose of advertising
+support for Barebox. This includes, but is not limited to, the following
+uses:
+ - systems that come preloaded with Barebox and such that support
+ Barebox through a flash upgrade.
+ - Barebox documentation
+ - posters, clothing, presentations and other promotion material referring to the
+ Barebox project
+
+Please make the image a link to http://www.barebox.org/ if you use it on a
+web page.
diff --git a/logo/png24/100x100/color/barebox.png b/logo/png24/100x100/color/barebox.png
new file mode 100644
index 0000000000..cc571fc6a4
--- /dev/null
+++ b/logo/png24/100x100/color/barebox.png
Binary files differ
diff --git a/logo/png24/100x100/white/barebox.png b/logo/png24/100x100/white/barebox.png
new file mode 100644
index 0000000000..e29678575c
--- /dev/null
+++ b/logo/png24/100x100/white/barebox.png
Binary files differ
diff --git a/logo/png24/200x200/color/barebox.png b/logo/png24/200x200/color/barebox.png
new file mode 100644
index 0000000000..1e00b8ca9a
--- /dev/null
+++ b/logo/png24/200x200/color/barebox.png
Binary files differ
diff --git a/logo/png24/200x200/white/barebox.png b/logo/png24/200x200/white/barebox.png
new file mode 100644
index 0000000000..03f1f86b00
--- /dev/null
+++ b/logo/png24/200x200/white/barebox.png
Binary files differ
diff --git a/logo/png24/400x400/color/barebox.png b/logo/png24/400x400/color/barebox.png
new file mode 100644
index 0000000000..9cb9db2e48
--- /dev/null
+++ b/logo/png24/400x400/color/barebox.png
Binary files differ
diff --git a/logo/png24/400x400/white/barebox.png b/logo/png24/400x400/white/barebox.png
new file mode 100644
index 0000000000..fbd89ee7af
--- /dev/null
+++ b/logo/png24/400x400/white/barebox.png
Binary files differ
diff --git a/logo/png24/600x600/color/barebox.png b/logo/png24/600x600/color/barebox.png
new file mode 100644
index 0000000000..5a0e553242
--- /dev/null
+++ b/logo/png24/600x600/color/barebox.png
Binary files differ
diff --git a/logo/png24/600x600/while/barebox.png b/logo/png24/600x600/while/barebox.png
new file mode 100644
index 0000000000..71105f62d3
--- /dev/null
+++ b/logo/png24/600x600/while/barebox.png
Binary files differ
diff --git a/logo/png24/800x800/color/barebox.png b/logo/png24/800x800/color/barebox.png
new file mode 100644
index 0000000000..aebca6bb0a
--- /dev/null
+++ b/logo/png24/800x800/color/barebox.png
Binary files differ
diff --git a/logo/png24/800x800/white/barebox.png b/logo/png24/800x800/white/barebox.png
new file mode 100644
index 0000000000..6fc76cb3d1
--- /dev/null
+++ b/logo/png24/800x800/white/barebox.png
Binary files differ
diff --git a/logo/png8/100x100/color/blackbg/barebox.png b/logo/png8/100x100/color/blackbg/barebox.png
new file mode 100644
index 0000000000..dd999e7077
--- /dev/null
+++ b/logo/png8/100x100/color/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/100x100/white/blackbg/barebox.png b/logo/png8/100x100/white/blackbg/barebox.png
new file mode 100644
index 0000000000..84c05e1012
--- /dev/null
+++ b/logo/png8/100x100/white/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/200x200/color/blackbg/barebox.png b/logo/png8/200x200/color/blackbg/barebox.png
new file mode 100644
index 0000000000..4a5868819b
--- /dev/null
+++ b/logo/png8/200x200/color/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/200x200/white/blackbg/barebox.png b/logo/png8/200x200/white/blackbg/barebox.png
new file mode 100644
index 0000000000..0afed11297
--- /dev/null
+++ b/logo/png8/200x200/white/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/400x400/color/blackbg/barebox.png b/logo/png8/400x400/color/blackbg/barebox.png
new file mode 100644
index 0000000000..4451769e99
--- /dev/null
+++ b/logo/png8/400x400/color/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/400x400/white/blackbg/barebox.png b/logo/png8/400x400/white/blackbg/barebox.png
new file mode 100644
index 0000000000..8fb2a91478
--- /dev/null
+++ b/logo/png8/400x400/white/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/600x600/color/blackbg/barebox.png b/logo/png8/600x600/color/blackbg/barebox.png
new file mode 100644
index 0000000000..79929b242c
--- /dev/null
+++ b/logo/png8/600x600/color/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/600x600/while/blackbg/barebox.png b/logo/png8/600x600/while/blackbg/barebox.png
new file mode 100644
index 0000000000..223da3e0cd
--- /dev/null
+++ b/logo/png8/600x600/while/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/800x800/color/blackbg/barebox.png b/logo/png8/800x800/color/blackbg/barebox.png
new file mode 100644
index 0000000000..2ffc11101c
--- /dev/null
+++ b/logo/png8/800x800/color/blackbg/barebox.png
Binary files differ
diff --git a/logo/png8/800x800/white/blackbg/barebox.png b/logo/png8/800x800/white/blackbg/barebox.png
new file mode 100644
index 0000000000..e164aac0ba
--- /dev/null
+++ b/logo/png8/800x800/white/blackbg/barebox.png
Binary files differ
diff --git a/net/dhcp.c b/net/dhcp.c
index 79efa3e30e..768255e184 100644
--- a/net/dhcp.c
+++ b/net/dhcp.c
@@ -19,6 +19,10 @@
#include <magicvar.h>
#include <linux/err.h>
#include <getopt.h>
+#include <globalvar.h>
+#include <init.h>
+
+#define DHCP_DEFAULT_RETRY 20
#define OPT_SIZE 312 /* Minimum DHCP Options size per RFC2131 - results in 576 byte pkt */
@@ -78,11 +82,39 @@ static IPaddr_t net_dhcp_server_ip;
static uint64_t dhcp_start;
static char dhcp_tftpname[256];
+static const char* dhcp_get_barebox_global(const char * var)
+{
+ char * var_global = asprintf("global.dhcp.%s", var);
+ const char *val;
+
+ if (!var_global)
+ return NULL;
+
+ val = getenv(var_global);
+ free(var_global);
+ return val;
+}
+
+static int dhcp_set_barebox_global(const char * var, char *val)
+{
+ char * var_global = asprintf("global.dhcp.%s", var);
+ int ret;
+
+ if (!var_global)
+ return -ENOMEM;
+
+ ret = setenv(var_global, val);
+ free(var_global);
+ return ret;
+}
+
struct dhcp_opt {
unsigned char option;
/* request automatically the option when creating the DHCP request */
bool optional;
+ bool copy_only_if_valid;
const char *barebox_var_name;
+ const char *barebox_dhcp_global;
void (*handle)(struct dhcp_opt *opt, unsigned char *data, int tlen);
void *data;
@@ -123,7 +155,15 @@ static void env_str_handle(struct dhcp_opt *opt, unsigned char *popt, int optlen
memcpy(tmp, popt, optlen);
tmp[optlen] = 0;
- setenv(opt->barebox_var_name, tmp);
+
+ if (opt->copy_only_if_valid && !strlen(tmp))
+ return;
+
+ if (opt->barebox_var_name)
+ setenv(opt->barebox_var_name, tmp);
+ if (opt->barebox_dhcp_global)
+ dhcp_set_barebox_global(opt->barebox_dhcp_global, tmp);
+
}
static void copy_uint32_handle(struct dhcp_opt *opt, unsigned char *popt, int optlen)
@@ -174,8 +214,9 @@ struct dhcp_opt dhcp_options[] = {
.barebox_var_name = "net.nameserver",
}, {
.option = 12,
+ .copy_only_if_valid = 1,
.handle = env_str_handle,
- .barebox_var_name = "hostname",
+ .barebox_var_name = "global.hostname",
}, {
.option = 15,
.handle = env_str_handle,
@@ -183,7 +224,7 @@ struct dhcp_opt dhcp_options[] = {
}, {
.option = 17,
.handle = env_str_handle,
- .barebox_var_name = "rootpath",
+ .barebox_dhcp_global = "rootpath",
}, {
.option = 51,
.handle = copy_uint32_handle,
@@ -196,22 +237,23 @@ struct dhcp_opt dhcp_options[] = {
}, {
.option = 66,
.handle = env_str_handle,
- .barebox_var_name = "dhcp_tftp_server_name",
+ .barebox_dhcp_global = "tftp_server_name",
.data = dhcp_tftpname,
}, {
.option = 67,
.handle = bootfile_vendorex_handle,
- .barebox_var_name = "bootfile",
+ .barebox_dhcp_global = "bootfile",
}, {
.option = 224,
.handle = env_str_handle,
- .barebox_var_name = "dhcp_oftree_file",
+ .barebox_dhcp_global = "oftree_file",
},
};
struct dhcp_param {
unsigned char option;
const char *barebox_var_name;
+ const char *barebox_dhcp_global;
int (*handle)(struct dhcp_param *param, u8 *e);
void *data;
};
@@ -224,6 +266,9 @@ static int dhcp_set_string_options(struct dhcp_param *param, u8 *e)
if (!str && param->barebox_var_name)
str = (char*)getenv(param->barebox_var_name);
+ if (!str && param->barebox_dhcp_global)
+ str = (char*)dhcp_get_barebox_global(param->barebox_dhcp_global);
+
if (!str)
return 0;
@@ -248,23 +293,23 @@ struct dhcp_param dhcp_params[] = {
{
.option = DHCP_HOSTNAME,
.handle = dhcp_set_string_options,
- .barebox_var_name = "hostname",
+ .barebox_var_name = "global.hostname",
}, {
.option = DHCP_VENDOR_ID,
.handle = dhcp_set_string_options,
- .barebox_var_name = "dhcp_vendor_id",
+ .barebox_dhcp_global = "vendor_id",
}, {
.option = DHCP_CLIENT_ID,
.handle = dhcp_set_string_options,
- .barebox_var_name = "dhcp_client_id",
+ .barebox_dhcp_global = "client_id",
}, {
.option = DHCP_USER_CLASS,
.handle = dhcp_set_string_options,
- .barebox_var_name = "dhcp_user_class",
+ .barebox_dhcp_global = "user_class",
}, {
.option = DHCP_CLIENT_UUID,
.handle = dhcp_set_string_options,
- .barebox_var_name = "dhcp_client_uuid",
+ .barebox_dhcp_global = "client_uuid",
}
};
@@ -345,8 +390,10 @@ static void bootp_copy_net_params(struct bootp *bp)
if (tmp_ip != 0)
net_set_serverip(tmp_ip);
- if (strlen(bp->bp_file) > 0)
+ if (strlen(bp->bp_file) > 0) {
setenv("bootfile", bp->bp_file);
+ dhcp_set_barebox_global("bootfile", bp->bp_file);
+ }
debug("bootfile: %s\n", bp->bp_file);
}
@@ -607,20 +654,74 @@ static void dhcp_reset_env(void)
for (i = 0; i < ARRAY_SIZE(dhcp_options); i++) {
opt = &dhcp_options[i];
- if (!opt->barebox_var_name)
+ if (!opt->barebox_var_name || opt->copy_only_if_valid)
continue;
setenv(opt->barebox_var_name,"");
+ if (opt->barebox_dhcp_global)
+ dhcp_set_barebox_global(opt->barebox_dhcp_global,"");
+ }
+}
+
+static void dhcp_global_add(const char *var)
+{
+ char * var_global = asprintf("dhcp.%s", var);
+
+ if (!var_global)
+ return;
+
+ globalvar_add_simple(var_global);
+ free(var_global);
+}
+
+static int dhcp_global_init(void)
+{
+ struct dhcp_opt *opt;
+ struct dhcp_param *param;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dhcp_options); i++) {
+ opt = &dhcp_options[i];
+
+ if (!opt->barebox_dhcp_global)
+ continue;
+
+ dhcp_global_add(opt->barebox_dhcp_global);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dhcp_params); i++) {
+ param = &dhcp_params[i];
+
+ if (!param->barebox_dhcp_global)
+ continue;
+
+ dhcp_global_add(param->barebox_dhcp_global);
}
+
+ return 0;
+}
+late_initcall(dhcp_global_init);
+
+static void dhcp_getenv_int(const char *name, int *i)
+{
+ const char* str = getenv(name);
+
+ if (!str)
+ return;
+
+ *i = simple_strtoul(str, NULL, 10);
}
static int do_dhcp(int argc, char *argv[])
{
int ret, opt;
+ int retries = DHCP_DEFAULT_RETRY;
dhcp_reset_env();
- while((opt = getopt(argc, argv, "H:v:c:u:U:")) > 0) {
+ dhcp_getenv_int("global.dhcp.retries", &retries);
+
+ while((opt = getopt(argc, argv, "H:v:c:u:U:r:")) > 0) {
switch(opt) {
case 'H':
dhcp_set_param_data(DHCP_HOSTNAME, optarg);
@@ -637,9 +738,17 @@ static int do_dhcp(int argc, char *argv[])
case 'U':
dhcp_set_param_data(DHCP_USER_CLASS, optarg);
break;
+ case 'r':
+ retries = simple_strtoul(optarg, NULL, 10);
+ break;
}
}
+ if (!retries) {
+ printf("retries is set to zero, set it to %d\n", DHCP_DEFAULT_RETRY);
+ retries = DHCP_DEFAULT_RETRY;
+ }
+
dhcp_con = net_udp_new(0xffffffff, PORT_BOOTPS, dhcp_handler, NULL);
if (IS_ERR(dhcp_con)) {
ret = PTR_ERR(dhcp_con);
@@ -660,11 +769,17 @@ static int do_dhcp(int argc, char *argv[])
while (dhcp_state != BOUND) {
if (ctrlc())
break;
+ if (!retries) {
+ ret = -ETIMEDOUT;
+ goto out1;
+ }
net_poll();
if (is_timeout(dhcp_start, 3 * SECOND)) {
dhcp_start = get_time_ns();
printf("T ");
ret = bootp_request();
+ /* no need to check if retries > 0 as we check if != 0 */
+ retries--;
if (ret)
goto out1;
}
@@ -676,7 +791,7 @@ out:
if (ret)
printf("dhcp failed: %s\n", strerror(-ret));
- return ret ? 1 : 0;
+ return ret;
}
BAREBOX_CMD_HELP_START(dhcp)
@@ -699,7 +814,8 @@ BAREBOX_CMD_HELP_OPT ("-u <client_uuid>",
BAREBOX_CMD_HELP_OPT ("-U <user_class>",
"DHCP User class (code 77) submitted in DHCP requests. It can\n"
"be used in the DHCP server's configuration to select options\n"
-"(e.g. bootfile or server) which are valid for barebox clients only.\n");
+"(e.g. bootfile or server) which are valid for barebox clients only.\n")
+BAREBOX_CMD_HELP_OPT ("-r <retry>", "retry limit by default "__stringify(DHCP_DEFAULT_RETRY)"\n");
BAREBOX_CMD_HELP_END
BAREBOX_CMD_START(dhcp)
@@ -709,12 +825,13 @@ BAREBOX_CMD_START(dhcp)
BAREBOX_CMD_COMPLETE(empty_complete)
BAREBOX_CMD_END
-BAREBOX_MAGICVAR(bootfile, "bootfile returned from DHCP request");
-BAREBOX_MAGICVAR(hostname, "hostname to send or returned from DHCP request");
-BAREBOX_MAGICVAR(rootpath, "rootpath returned from DHCP request");
-BAREBOX_MAGICVAR(dhcp_vendor_id, "vendor id to send to the DHCP server");
-BAREBOX_MAGICVAR(dhcp_client_uuid, "cliend uuid to send to the DHCP server");
-BAREBOX_MAGICVAR(dhcp_client_id, "cliend id to send to the DHCP server");
-BAREBOX_MAGICVAR(dhcp_user_class, "user class to send to the DHCP server");
-BAREBOX_MAGICVAR(dhcp_tftp_server_name, "TFTP server Name returned from DHCP request");
-BAREBOX_MAGICVAR(dhcp_oftree_file, "OF tree returned from DHCP request (option 224)");
+BAREBOX_MAGICVAR_NAMED(global_hostname, global.hostname, "hostname to send or returned from DHCP request");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_bootfile, global.dhcp.bootfile, "bootfile returned from DHCP request");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_rootpath, global.dhcp.rootpath, "rootpath returned from DHCP request");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_vendor_id, global.dhcp.vendor_id, "vendor id to send to the DHCP server");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_client_uuid, global.dhcp.client_uuid, "cliend uuid to send to the DHCP server");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_client_id, global.dhcp.client_id, "cliend id to send to the DHCP server");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_user_class, global.dhcp.user_class, "user class to send to the DHCP server");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_tftp_server_name, global.dhcp.tftp_server_name, "TFTP server Name returned from DHCP request");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_oftree_file, global.dhcp.oftree_file, "OF tree returned from DHCP request (option 224)");
+BAREBOX_MAGICVAR_NAMED(global_dhcp_retries, global.dhcp.retries, "retry limit");
diff --git a/net/eth.c b/net/eth.c
index 94b88cd8ff..220edcfade 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -23,11 +23,12 @@
#include <driver.h>
#include <init.h>
#include <net.h>
-#include <miidev.h>
+#include <linux/phy.h>
#include <errno.h>
#include <malloc.h>
static struct eth_device *eth_current;
+static uint64_t last_link_check;
static LIST_HEAD(netdev_list);
@@ -124,20 +125,64 @@ int eth_complete(struct string_list *sl, char *instr)
}
#endif
-int eth_send(void *packet, int length)
+/*
+ * Check for link if we haven't done so for longer.
+ */
+static int eth_carrier_check(int force)
{
int ret;
- if (!eth_current)
- return -ENODEV;
+ if (!IS_ENABLED(CONFIG_PHYLIB))
+ return 0;
+
+ if (!eth_current->phydev)
+ return 0;
- if (!eth_current->active) {
- ret = eth_current->open(eth_current);
+ if (force || is_timeout(last_link_check, 5 * SECOND)) {
+ ret = phy_update_status(eth_current->phydev);
if (ret)
return ret;
- eth_current->active = 1;
+ last_link_check = get_time_ns();
}
+ return eth_current->phydev->link ? 0 : -ENETDOWN;
+}
+
+/*
+ * Check if we have a current ethernet device and
+ * eventually open it if we have to.
+ */
+static int eth_check_open(void)
+{
+ int ret;
+
+ if (!eth_current)
+ return -ENODEV;
+
+ if (eth_current->active)
+ return 0;
+
+ ret = eth_current->open(eth_current);
+ if (ret)
+ return ret;
+
+ eth_current->active = 1;
+
+ return eth_carrier_check(1);
+}
+
+int eth_send(void *packet, int length)
+{
+ int ret;
+
+ ret = eth_check_open();
+ if (ret)
+ return ret;
+
+ ret = eth_carrier_check(0);
+ if (ret)
+ return ret;
+
led_trigger_network(LED_TRIGGER_NET_TX);
return eth_current->send(eth_current, packet, length);
@@ -147,15 +192,13 @@ int eth_rx(void)
{
int ret;
- if (!eth_current)
- return -ENODEV;
+ ret = eth_check_open();
+ if (ret)
+ return ret;
- if (!eth_current->active) {
- ret = eth_current->open(eth_current);
- if (ret)
- return ret;
- eth_current->active = 1;
- }
+ ret = eth_carrier_check(0);
+ if (ret)
+ return ret;
return eth_current->recv(eth_current);
}
diff --git a/net/net.c b/net/net.c
index b5885fb2aa..3ac098fcff 100644
--- a/net/net.c
+++ b/net/net.c
@@ -216,6 +216,7 @@ static int arp_request(IPaddr_t dest, unsigned char *ether)
static char *arp_packet;
struct ethernet *et;
unsigned retries = 0;
+ int ret;
if (!arp_packet) {
arp_packet = net_alloc_packet();
@@ -259,7 +260,9 @@ static int arp_request(IPaddr_t dest, unsigned char *ether)
arp_ether = ether;
- eth_send(arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+ ret = eth_send(arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+ if (ret)
+ return ret;
arp_start = get_time_ns();
while (arp_wait_ip) {
@@ -269,7 +272,9 @@ static int arp_request(IPaddr_t dest, unsigned char *ether)
if (is_timeout(arp_start, 3 * SECOND)) {
printf("T ");
arp_start = get_time_ns();
- eth_send(arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+ ret = eth_send(arp_packet, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+ if (ret)
+ return ret;
retries++;
}
@@ -451,9 +456,7 @@ static int net_ip_send(struct net_connection *con, int len)
con->ip->check = 0;
con->ip->check = ~net_checksum((unsigned char *)con->ip, sizeof(struct iphdr));
- eth_send(con->packet, ETHER_HDR_SIZE + sizeof(struct iphdr) + len);
-
- return 0;
+ return eth_send(con->packet, ETHER_HDR_SIZE + sizeof(struct iphdr) + len);
}
int net_udp_send(struct net_connection *con, int len)
@@ -477,6 +480,7 @@ static int net_answer_arp(unsigned char *pkt, int len)
struct arprequest *arp = (struct arprequest *)(pkt + ETHER_HDR_SIZE);
struct ethernet *et = (struct ethernet *)pkt;
unsigned char *packet;
+ int ret;
debug("%s\n", __func__);
@@ -494,10 +498,10 @@ static int net_answer_arp(unsigned char *pkt, int len)
if (!packet)
return 0;
memcpy(packet, pkt, ETHER_HDR_SIZE + ARP_HDR_SIZE);
- eth_send(packet, ETHER_HDR_SIZE + ARP_HDR_SIZE);
+ ret = eth_send(packet, ETHER_HDR_SIZE + ARP_HDR_SIZE);
free(packet);
- return 0;
+ return ret;
}
static void net_bad_packet(unsigned char *pkt, int len)
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 6e63f85792..3f1cbdb912 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -2,6 +2,7 @@ bareboxenv
bin2c
gen_netx_image
kallsyms
+mk-am35xx-spi-image
mkimage
mkublheader
omap_signGP
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 912cfd83db..c7faf67a2b 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -209,7 +209,7 @@ endif
# >$< substitution to preserve $ when reloading .cmd file
# note: when using inline perl scripts [perl -e '...$$t=1;...']
# in $(cmd_xxx) double $$ your perl vars
-make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
+make-cmd = $(subst \\,\\\\,$(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1))))))
# Find any prerequisites that is newer than target or that does not exist.
# PHONY targets skipped in both cases.
diff --git a/scripts/Makefile b/scripts/Makefile
index 7ca5e2973d..55ccdac539 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -9,7 +9,7 @@ hostprogs-y += bin2c
hostprogs-y += mkimage
hostprogs-y += bareboxenv
hostprogs-$(CONFIG_ARCH_NETX) += gen_netx_image
-hostprogs-$(CONFIG_ARCH_OMAP) += omap_signGP
+hostprogs-$(CONFIG_ARCH_OMAP) += omap_signGP mk-am35xx-spi-image
hostprogs-$(CONFIG_ARCH_S5PCxx) += s5p_cksum
hostprogs-$(CONFIG_ARCH_DAVINCI) += mkublheader
diff --git a/scripts/genenv b/scripts/genenv
index c84af0c015..ff7972bb95 100755
--- a/scripts/genenv
+++ b/scripts/genenv
@@ -11,7 +11,11 @@ shift 2
tempdir=$(mktemp -d tmp.XXXXXX)
for i in $*; do
- cp -r $i/* $tempdir
+ if [ -d $i ]; then
+ cp -r $i/* $tempdir
+ else
+ cp -a $i $tempdir
+ fi
done
find $tempdir -name '.svn' -o -name '*~' | xargs --no-run-if-empty rm -r
diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore
index 624f6502e0..9cd51202ac 100644
--- a/scripts/kconfig/.gitignore
+++ b/scripts/kconfig/.gitignore
@@ -3,6 +3,7 @@
#
config*
lex.*.c
+*.lex.c
*.tab.c
*.tab.h
zconf.hash.c
diff --git a/scripts/kconfig/zconf.lex.c b/scripts/kconfig/zconf.lex.c
deleted file mode 100644
index c32b1a49f5..0000000000
--- a/scripts/kconfig/zconf.lex.c
+++ /dev/null
@@ -1,2420 +0,0 @@
-
-#line 3 "scripts/kconfig/zconf.lex.c_shipped"
-
-#define YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define yy_create_buffer zconf_create_buffer
-#define yy_delete_buffer zconf_delete_buffer
-#define yy_flex_debug zconf_flex_debug
-#define yy_init_buffer zconf_init_buffer
-#define yy_flush_buffer zconf_flush_buffer
-#define yy_load_buffer_state zconf_load_buffer_state
-#define yy_switch_to_buffer zconf_switch_to_buffer
-#define yyin zconfin
-#define yyleng zconfleng
-#define yylex zconflex
-#define yylineno zconflineno
-#define yyout zconfout
-#define yyrestart zconfrestart
-#define yytext zconftext
-#define yywrap zconfwrap
-#define yyalloc zconfalloc
-#define yyrealloc zconfrealloc
-#define yyfree zconffree
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-#endif /* ! C99 */
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX (4294967295U)
-#endif
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index. If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition. This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN (yy_start) = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state. The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START (((yy_start) - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE zconfrestart(zconfin )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#define YY_BUF_SIZE 16384
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-extern int zconfleng;
-
-extern FILE *zconfin, *zconfout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
- #define YY_LESS_LINENO(n)
-
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up zconftext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- *yy_cp = (yy_hold_char); \
- YY_RESTORE_YY_MORE_OFFSET \
- (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
- YY_DO_BEFORE_ACTION; /* set up zconftext again */ \
- } \
- while ( 0 )
-
-#define unput(c) yyunput( c, (yytext_ptr) )
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
- {
- FILE *yy_input_file;
-
- char *yy_ch_buf; /* input buffer */
- char *yy_buf_pos; /* current position in input buffer */
-
- /* Size of input buffer in bytes, not including room for EOB
- * characters.
- */
- yy_size_t yy_buf_size;
-
- /* Number of characters read into yy_ch_buf, not including EOB
- * characters.
- */
- int yy_n_chars;
-
- /* Whether we "own" the buffer - i.e., we know we created it,
- * and can realloc() it to grow it, and should free() it to
- * delete it.
- */
- int yy_is_our_buffer;
-
- /* Whether this is an "interactive" input source; if so, and
- * if we're using stdio for input, then we want to use getc()
- * instead of fread(), to make sure we stop fetching input after
- * each newline.
- */
- int yy_is_interactive;
-
- /* Whether we're considered to be at the beginning of a line.
- * If so, '^' rules will be active on the next match, otherwise
- * not.
- */
- int yy_at_bol;
-
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
- /* Whether to try to fill the input buffer when we reach the
- * end of it.
- */
- int yy_fill_buffer;
-
- int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
- /* When an EOF's been seen but there's still some text to process
- * then we mark the buffer as YY_EOF_PENDING, to indicate that we
- * shouldn't try reading from the input source any more. We might
- * still have a bunch of tokens to match, though, because of
- * possible backing-up.
- *
- * When we actually see the EOF, we change the status to "new"
- * (via zconfrestart()), so that the user can continue scanning by
- * just pointing zconfin at a new input file.
- */
-#define YY_BUFFER_EOF_PENDING 2
-
- };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
- ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
- : NULL)
-
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-
-/* yy_hold_char holds the character lost when zconftext is formed. */
-static char yy_hold_char;
-static int yy_n_chars; /* number of characters read into yy_ch_buf */
-int zconfleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 0; /* whether we need to initialize */
-static int yy_start = 0; /* start state number */
-
-/* Flag which is used to allow zconfwrap()'s to do buffer switches
- * instead of setting up a fresh zconfin. A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void zconfrestart (FILE *input_file );
-void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer );
-YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size );
-void zconf_delete_buffer (YY_BUFFER_STATE b );
-void zconf_flush_buffer (YY_BUFFER_STATE b );
-void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer );
-void zconfpop_buffer_state (void );
-
-static void zconfensure_buffer_stack (void );
-static void zconf_load_buffer_state (void );
-static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file );
-
-#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER )
-
-YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size );
-YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str );
-YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len );
-
-void *zconfalloc (yy_size_t );
-void *zconfrealloc (void *,yy_size_t );
-void zconffree (void * );
-
-#define yy_new_buffer zconf_create_buffer
-
-#define yy_set_interactive(is_interactive) \
- { \
- if ( ! YY_CURRENT_BUFFER ){ \
- zconfensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
- }
-
-#define yy_set_bol(at_bol) \
- { \
- if ( ! YY_CURRENT_BUFFER ){\
- zconfensure_buffer_stack (); \
- YY_CURRENT_BUFFER_LVALUE = \
- zconf_create_buffer(zconfin,YY_BUF_SIZE ); \
- } \
- YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
- }
-
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-/* Begin user sect3 */
-
-#define zconfwrap(n) 1
-#define YY_SKIP_YYWRAP
-
-typedef unsigned char YY_CHAR;
-
-FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0;
-
-typedef int yy_state_type;
-
-extern int zconflineno;
-
-int zconflineno = 1;
-
-extern char *zconftext;
-#define yytext_ptr zconftext
-static yyconst flex_int16_t yy_nxt[][17] =
- {
- {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0
- },
-
- {
- 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12
- },
-
- {
- 11, 12, 13, 14, 12, 12, 15, 12, 12, 12,
- 12, 12, 12, 12, 12, 12, 12
- },
-
- {
- 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 18, 16, 16, 16
- },
-
- {
- 11, 16, 16, 17, 16, 16, 16, 16, 16, 16,
- 16, 16, 16, 18, 16, 16, 16
-
- },
-
- {
- 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19
- },
-
- {
- 11, 19, 20, 21, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 19
- },
-
- {
- 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
- 22, 22, 22, 22, 22, 25, 22
- },
-
- {
- 11, 22, 22, 23, 22, 24, 22, 22, 24, 22,
- 22, 22, 22, 22, 22, 25, 22
- },
-
- {
- 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
- 33, 34, 35, 35, 36, 37, 38
-
- },
-
- {
- 11, 26, 26, 27, 28, 29, 30, 31, 29, 32,
- 33, 34, 35, 35, 36, 37, 38
- },
-
- {
- -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
- -11, -11, -11, -11, -11, -11, -11
- },
-
- {
- 11, -12, -12, -12, -12, -12, -12, -12, -12, -12,
- -12, -12, -12, -12, -12, -12, -12
- },
-
- {
- 11, -13, 39, 40, -13, -13, 41, -13, -13, -13,
- -13, -13, -13, -13, -13, -13, -13
- },
-
- {
- 11, -14, -14, -14, -14, -14, -14, -14, -14, -14,
- -14, -14, -14, -14, -14, -14, -14
-
- },
-
- {
- 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42
- },
-
- {
- 11, -16, -16, -16, -16, -16, -16, -16, -16, -16,
- -16, -16, -16, -16, -16, -16, -16
- },
-
- {
- 11, -17, -17, -17, -17, -17, -17, -17, -17, -17,
- -17, -17, -17, -17, -17, -17, -17
- },
-
- {
- 11, -18, -18, -18, -18, -18, -18, -18, -18, -18,
- -18, -18, -18, 44, -18, -18, -18
- },
-
- {
- 11, 45, 45, -19, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45
-
- },
-
- {
- 11, -20, 46, 47, -20, -20, -20, -20, -20, -20,
- -20, -20, -20, -20, -20, -20, -20
- },
-
- {
- 11, 48, -21, -21, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48
- },
-
- {
- 11, 49, 49, 50, 49, -22, 49, 49, -22, 49,
- 49, 49, 49, 49, 49, -22, 49
- },
-
- {
- 11, -23, -23, -23, -23, -23, -23, -23, -23, -23,
- -23, -23, -23, -23, -23, -23, -23
- },
-
- {
- 11, -24, -24, -24, -24, -24, -24, -24, -24, -24,
- -24, -24, -24, -24, -24, -24, -24
-
- },
-
- {
- 11, 51, 51, 52, 51, 51, 51, 51, 51, 51,
- 51, 51, 51, 51, 51, 51, 51
- },
-
- {
- 11, -26, -26, -26, -26, -26, -26, -26, -26, -26,
- -26, -26, -26, -26, -26, -26, -26
- },
-
- {
- 11, -27, -27, -27, -27, -27, -27, -27, -27, -27,
- -27, -27, -27, -27, -27, -27, -27
- },
-
- {
- 11, -28, -28, -28, -28, -28, -28, -28, -28, -28,
- -28, -28, -28, -28, 53, -28, -28
- },
-
- {
- 11, -29, -29, -29, -29, -29, -29, -29, -29, -29,
- -29, -29, -29, -29, -29, -29, -29
-
- },
-
- {
- 11, 54, 54, -30, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54
- },
-
- {
- 11, -31, -31, -31, -31, -31, -31, 55, -31, -31,
- -31, -31, -31, -31, -31, -31, -31
- },
-
- {
- 11, -32, -32, -32, -32, -32, -32, -32, -32, -32,
- -32, -32, -32, -32, -32, -32, -32
- },
-
- {
- 11, -33, -33, -33, -33, -33, -33, -33, -33, -33,
- -33, -33, -33, -33, -33, -33, -33
- },
-
- {
- 11, -34, -34, -34, -34, -34, -34, -34, -34, -34,
- -34, 56, 57, 57, -34, -34, -34
-
- },
-
- {
- 11, -35, -35, -35, -35, -35, -35, -35, -35, -35,
- -35, 57, 57, 57, -35, -35, -35
- },
-
- {
- 11, -36, -36, -36, -36, -36, -36, -36, -36, -36,
- -36, -36, -36, -36, -36, -36, -36
- },
-
- {
- 11, -37, -37, 58, -37, -37, -37, -37, -37, -37,
- -37, -37, -37, -37, -37, -37, -37
- },
-
- {
- 11, -38, -38, -38, -38, -38, -38, -38, -38, -38,
- -38, -38, -38, -38, -38, -38, 59
- },
-
- {
- 11, -39, 39, 40, -39, -39, 41, -39, -39, -39,
- -39, -39, -39, -39, -39, -39, -39
-
- },
-
- {
- 11, -40, -40, -40, -40, -40, -40, -40, -40, -40,
- -40, -40, -40, -40, -40, -40, -40
- },
-
- {
- 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42
- },
-
- {
- 11, 42, 42, 43, 42, 42, 42, 42, 42, 42,
- 42, 42, 42, 42, 42, 42, 42
- },
-
- {
- 11, -43, -43, -43, -43, -43, -43, -43, -43, -43,
- -43, -43, -43, -43, -43, -43, -43
- },
-
- {
- 11, -44, -44, -44, -44, -44, -44, -44, -44, -44,
- -44, -44, -44, 44, -44, -44, -44
-
- },
-
- {
- 11, 45, 45, -45, 45, 45, 45, 45, 45, 45,
- 45, 45, 45, 45, 45, 45, 45
- },
-
- {
- 11, -46, 46, 47, -46, -46, -46, -46, -46, -46,
- -46, -46, -46, -46, -46, -46, -46
- },
-
- {
- 11, 48, -47, -47, 48, 48, 48, 48, 48, 48,
- 48, 48, 48, 48, 48, 48, 48
- },
-
- {
- 11, -48, -48, -48, -48, -48, -48, -48, -48, -48,
- -48, -48, -48, -48, -48, -48, -48
- },
-
- {
- 11, 49, 49, 50, 49, -49, 49, 49, -49, 49,
- 49, 49, 49, 49, 49, -49, 49
-
- },
-
- {
- 11, -50, -50, -50, -50, -50, -50, -50, -50, -50,
- -50, -50, -50, -50, -50, -50, -50
- },
-
- {
- 11, -51, -51, 52, -51, -51, -51, -51, -51, -51,
- -51, -51, -51, -51, -51, -51, -51
- },
-
- {
- 11, -52, -52, -52, -52, -52, -52, -52, -52, -52,
- -52, -52, -52, -52, -52, -52, -52
- },
-
- {
- 11, -53, -53, -53, -53, -53, -53, -53, -53, -53,
- -53, -53, -53, -53, -53, -53, -53
- },
-
- {
- 11, 54, 54, -54, 54, 54, 54, 54, 54, 54,
- 54, 54, 54, 54, 54, 54, 54
-
- },
-
- {
- 11, -55, -55, -55, -55, -55, -55, -55, -55, -55,
- -55, -55, -55, -55, -55, -55, -55
- },
-
- {
- 11, -56, -56, -56, -56, -56, -56, -56, -56, -56,
- -56, 60, 57, 57, -56, -56, -56
- },
-
- {
- 11, -57, -57, -57, -57, -57, -57, -57, -57, -57,
- -57, 57, 57, 57, -57, -57, -57
- },
-
- {
- 11, -58, -58, -58, -58, -58, -58, -58, -58, -58,
- -58, -58, -58, -58, -58, -58, -58
- },
-
- {
- 11, -59, -59, -59, -59, -59, -59, -59, -59, -59,
- -59, -59, -59, -59, -59, -59, -59
-
- },
-
- {
- 11, -60, -60, -60, -60, -60, -60, -60, -60, -60,
- -60, 57, 57, 57, -60, -60, -60
- },
-
- } ;
-
-static yy_state_type yy_get_previous_state (void );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
-static int yy_get_next_buffer (void );
-static void yy_fatal_error (yyconst char msg[] );
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up zconftext.
- */
-#define YY_DO_BEFORE_ACTION \
- (yytext_ptr) = yy_bp; \
- zconfleng = (size_t) (yy_cp - yy_bp); \
- (yy_hold_char) = *yy_cp; \
- *yy_cp = '\0'; \
- (yy_c_buf_p) = yy_cp;
-
-#define YY_NUM_RULES 33
-#define YY_END_OF_BUFFER 34
-/* This struct is not used in this scanner,
- but its presence is necessary. */
-struct yy_trans_info
- {
- flex_int32_t yy_verify;
- flex_int32_t yy_nxt;
- };
-static yyconst flex_int16_t yy_accept[61] =
- { 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 34, 5, 4, 2, 3, 7, 8, 6, 32, 29,
- 31, 24, 28, 27, 26, 22, 17, 13, 16, 20,
- 22, 11, 12, 19, 19, 14, 22, 22, 4, 2,
- 3, 3, 1, 6, 32, 29, 31, 30, 24, 23,
- 26, 25, 15, 20, 9, 19, 19, 21, 10, 18
- } ;
-
-static yyconst flex_int32_t yy_ec[256] =
- { 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 2, 4, 5, 6, 1, 1, 7, 8, 9,
- 10, 1, 1, 1, 11, 12, 12, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 1, 1, 1,
- 14, 1, 1, 1, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 1, 15, 1, 1, 13, 1, 13, 13, 13, 13,
-
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
- 13, 13, 1, 16, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1
- } ;
-
-extern int zconf_flex_debug;
-int zconf_flex_debug = 0;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *zconftext;
-#define YY_NO_INPUT 1
-
-/*
- * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
- * Released under the terms of the GNU GPL v2.0.
- */
-
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "lkc.h"
-
-#define START_STRSIZE 16
-
-static struct {
- struct file *file;
- int lineno;
-} current_pos;
-
-static char *text;
-static int text_size, text_asize;
-
-struct buffer {
- struct buffer *parent;
- YY_BUFFER_STATE state;
-};
-
-struct buffer *current_buf;
-
-static int last_ts, first_ts;
-
-static void zconf_endhelp(void);
-static void zconf_endfile(void);
-
-static void new_string(void)
-{
- text = malloc(START_STRSIZE);
- text_asize = START_STRSIZE;
- text_size = 0;
- *text = 0;
-}
-
-static void append_string(const char *str, int size)
-{
- int new_size = text_size + size + 1;
- if (new_size > text_asize) {
- new_size += START_STRSIZE - 1;
- new_size &= -START_STRSIZE;
- text = realloc(text, new_size);
- text_asize = new_size;
- }
- memcpy(text + text_size, str, size);
- text_size += size;
- text[text_size] = 0;
-}
-
-static void alloc_string(const char *str, int size)
-{
- text = malloc(size + 1);
- memcpy(text, str, size);
- text[size] = 0;
-}
-
-#define INITIAL 0
-#define COMMAND 1
-#define HELP 2
-#define STRING 3
-#define PARAM 4
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-static int yy_init_globals (void );
-
-/* Accessor methods to globals.
- These are made visible to non-reentrant scanners for convenience. */
-
-int zconflex_destroy (void );
-
-int zconfget_debug (void );
-
-void zconfset_debug (int debug_flag );
-
-YY_EXTRA_TYPE zconfget_extra (void );
-
-void zconfset_extra (YY_EXTRA_TYPE user_defined );
-
-FILE *zconfget_in (void );
-
-void zconfset_in (FILE * in_str );
-
-FILE *zconfget_out (void );
-
-void zconfset_out (FILE * out_str );
-
-int zconfget_leng (void );
-
-char *zconfget_text (void );
-
-int zconfget_lineno (void );
-
-void zconfset_lineno (int line_number );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int zconfwrap (void );
-#else
-extern int zconfwrap (void );
-#endif
-#endif
-
- static void yyunput (int c,char *buf_ptr );
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
-#endif
-
-#ifndef YY_NO_INPUT
-
-#ifdef __cplusplus
-static int yyinput (void );
-#else
-static int input (void );
-#endif
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#define YY_READ_BUF_SIZE 8192
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0)
-#endif
-
-/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
- errno=0; \
- while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \
- { \
- if( errno != EINTR) \
- { \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- break; \
- } \
- errno=0; \
- clearerr(zconfin); \
- }\
-\
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* end tables serialization structures and prototypes */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int zconflex (void);
-
-#define YY_DECL int zconflex (void)
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after zconftext and zconfleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
- YY_USER_ACTION
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
- register yy_state_type yy_current_state;
- register char *yy_cp, *yy_bp;
- register int yy_act;
-
- int str = 0;
- int ts, i;
-
- if ( !(yy_init) )
- {
- (yy_init) = 1;
-
-#ifdef YY_USER_INIT
- YY_USER_INIT;
-#endif
-
- if ( ! (yy_start) )
- (yy_start) = 1; /* first start state */
-
- if ( ! zconfin )
- zconfin = stdin;
-
- if ( ! zconfout )
- zconfout = stdout;
-
- if ( ! YY_CURRENT_BUFFER ) {
- zconfensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- zconf_create_buffer(zconfin,YY_BUF_SIZE );
- }
-
- zconf_load_buffer_state( );
- }
-
- while ( 1 ) /* loops until end-of-file is reached */
- {
- yy_cp = (yy_c_buf_p);
-
- /* Support of zconftext. */
- *yy_cp = (yy_hold_char);
-
- /* yy_bp points to the position in yy_ch_buf of the start of
- * the current run.
- */
- yy_bp = yy_cp;
-
- yy_current_state = (yy_start);
-yy_match:
- while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 )
- ++yy_cp;
-
- yy_current_state = -yy_current_state;
-
-yy_find_action:
- yy_act = yy_accept[yy_current_state];
-
- YY_DO_BEFORE_ACTION;
-
-do_action: /* This label is used only to access EOF actions. */
-
- switch ( yy_act )
- { /* beginning of action switch */
-case 1:
-/* rule 1 can match eol */
-case 2:
-/* rule 2 can match eol */
-YY_RULE_SETUP
-{
- current_file->lineno++;
- return T_EOL;
-}
- YY_BREAK
-case 3:
-YY_RULE_SETUP
-
- YY_BREAK
-case 4:
-YY_RULE_SETUP
-{
- BEGIN(COMMAND);
-}
- YY_BREAK
-case 5:
-YY_RULE_SETUP
-{
- unput(zconftext[0]);
- BEGIN(COMMAND);
-}
- YY_BREAK
-
-case 6:
-YY_RULE_SETUP
-{
- const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
- BEGIN(PARAM);
- current_pos.file = current_file;
- current_pos.lineno = current_file->lineno;
- if (id && id->flags & TF_COMMAND) {
- zconflval.id = id;
- return id->token;
- }
- alloc_string(zconftext, zconfleng);
- zconflval.string = text;
- return T_WORD;
- }
- YY_BREAK
-case 7:
-YY_RULE_SETUP
-
- YY_BREAK
-case 8:
-/* rule 8 can match eol */
-YY_RULE_SETUP
-{
- BEGIN(INITIAL);
- current_file->lineno++;
- return T_EOL;
- }
- YY_BREAK
-
-case 9:
-YY_RULE_SETUP
-return T_AND;
- YY_BREAK
-case 10:
-YY_RULE_SETUP
-return T_OR;
- YY_BREAK
-case 11:
-YY_RULE_SETUP
-return T_OPEN_PAREN;
- YY_BREAK
-case 12:
-YY_RULE_SETUP
-return T_CLOSE_PAREN;
- YY_BREAK
-case 13:
-YY_RULE_SETUP
-return T_NOT;
- YY_BREAK
-case 14:
-YY_RULE_SETUP
-return T_EQUAL;
- YY_BREAK
-case 15:
-YY_RULE_SETUP
-return T_UNEQUAL;
- YY_BREAK
-case 16:
-YY_RULE_SETUP
-{
- str = zconftext[0];
- new_string();
- BEGIN(STRING);
- }
- YY_BREAK
-case 17:
-/* rule 17 can match eol */
-YY_RULE_SETUP
-BEGIN(INITIAL); current_file->lineno++; return T_EOL;
- YY_BREAK
-case 18:
-YY_RULE_SETUP
-/* ignore */
- YY_BREAK
-case 19:
-YY_RULE_SETUP
-{
- const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng);
- if (id && id->flags & TF_PARAM) {
- zconflval.id = id;
- return id->token;
- }
- alloc_string(zconftext, zconfleng);
- zconflval.string = text;
- return T_WORD;
- }
- YY_BREAK
-case 20:
-YY_RULE_SETUP
-/* comment */
- YY_BREAK
-case 21:
-/* rule 21 can match eol */
-YY_RULE_SETUP
-current_file->lineno++;
- YY_BREAK
-case 22:
-YY_RULE_SETUP
-
- YY_BREAK
-case YY_STATE_EOF(PARAM):
-{
- BEGIN(INITIAL);
- }
- YY_BREAK
-
-case 23:
-/* rule 23 can match eol */
-*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
-(yy_c_buf_p) = yy_cp -= 1;
-YY_DO_BEFORE_ACTION; /* set up zconftext again */
-YY_RULE_SETUP
-{
- append_string(zconftext, zconfleng);
- zconflval.string = text;
- return T_WORD_QUOTE;
- }
- YY_BREAK
-case 24:
-YY_RULE_SETUP
-{
- append_string(zconftext, zconfleng);
- }
- YY_BREAK
-case 25:
-/* rule 25 can match eol */
-*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
-(yy_c_buf_p) = yy_cp -= 1;
-YY_DO_BEFORE_ACTION; /* set up zconftext again */
-YY_RULE_SETUP
-{
- append_string(zconftext + 1, zconfleng - 1);
- zconflval.string = text;
- return T_WORD_QUOTE;
- }
- YY_BREAK
-case 26:
-YY_RULE_SETUP
-{
- append_string(zconftext + 1, zconfleng - 1);
- }
- YY_BREAK
-case 27:
-YY_RULE_SETUP
-{
- if (str == zconftext[0]) {
- BEGIN(PARAM);
- zconflval.string = text;
- return T_WORD_QUOTE;
- } else
- append_string(zconftext, 1);
- }
- YY_BREAK
-case 28:
-/* rule 28 can match eol */
-YY_RULE_SETUP
-{
- printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
- current_file->lineno++;
- BEGIN(INITIAL);
- return T_EOL;
- }
- YY_BREAK
-case YY_STATE_EOF(STRING):
-{
- BEGIN(INITIAL);
- }
- YY_BREAK
-
-case 29:
-YY_RULE_SETUP
-{
- ts = 0;
- for (i = 0; i < zconfleng; i++) {
- if (zconftext[i] == '\t')
- ts = (ts & ~7) + 8;
- else
- ts++;
- }
- last_ts = ts;
- if (first_ts) {
- if (ts < first_ts) {
- zconf_endhelp();
- return T_HELPTEXT;
- }
- ts -= first_ts;
- while (ts > 8) {
- append_string(" ", 8);
- ts -= 8;
- }
- append_string(" ", ts);
- }
- }
- YY_BREAK
-case 30:
-/* rule 30 can match eol */
-*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */
-(yy_c_buf_p) = yy_cp -= 1;
-YY_DO_BEFORE_ACTION; /* set up zconftext again */
-YY_RULE_SETUP
-{
- current_file->lineno++;
- zconf_endhelp();
- return T_HELPTEXT;
- }
- YY_BREAK
-case 31:
-/* rule 31 can match eol */
-YY_RULE_SETUP
-{
- current_file->lineno++;
- append_string("\n", 1);
- }
- YY_BREAK
-case 32:
-YY_RULE_SETUP
-{
- while (zconfleng) {
- if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t'))
- break;
- zconfleng--;
- }
- append_string(zconftext, zconfleng);
- if (!first_ts)
- first_ts = last_ts;
- }
- YY_BREAK
-case YY_STATE_EOF(HELP):
-{
- zconf_endhelp();
- return T_HELPTEXT;
- }
- YY_BREAK
-
-case YY_STATE_EOF(INITIAL):
-case YY_STATE_EOF(COMMAND):
-{
- if (current_file) {
- zconf_endfile();
- return T_EOL;
- }
- fclose(zconfin);
- yyterminate();
-}
- YY_BREAK
-case 33:
-YY_RULE_SETUP
-YY_FATAL_ERROR( "flex scanner jammed" );
- YY_BREAK
-
- case YY_END_OF_BUFFER:
- {
- /* Amount of text matched not including the EOB char. */
- int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
-
- /* Undo the effects of YY_DO_BEFORE_ACTION. */
- *yy_cp = (yy_hold_char);
- YY_RESTORE_YY_MORE_OFFSET
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
- {
- /* We're scanning a new file or input source. It's
- * possible that this happened because the user
- * just pointed zconfin at a new source and called
- * zconflex(). If so, then we have to assure
- * consistency between YY_CURRENT_BUFFER and our
- * globals. Here is the right place to do so, because
- * this is the first action (other than possibly a
- * back-up) that will match for the new input source.
- */
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
- }
-
- /* Note that here we test for yy_c_buf_p "<=" to the position
- * of the first EOB in the buffer, since yy_c_buf_p will
- * already have been incremented past the NUL character
- * (since all states make transitions on EOB to the
- * end-of-buffer state). Contrast this with the test
- * in input().
- */
- if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- { /* This was really a NUL. */
- yy_state_type yy_next_state;
-
- (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- /* Okay, we're now positioned to make the NUL
- * transition. We couldn't have
- * yy_get_previous_state() go ahead and do it
- * for us because it doesn't know how to deal
- * with the possibility of jamming (and we don't
- * want to build jamming into it because then it
- * will run more slowly).
- */
-
- yy_next_state = yy_try_NUL_trans( yy_current_state );
-
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-
- if ( yy_next_state )
- {
- /* Consume the NUL. */
- yy_cp = ++(yy_c_buf_p);
- yy_current_state = yy_next_state;
- goto yy_match;
- }
-
- else
- {
- yy_cp = (yy_c_buf_p);
- goto yy_find_action;
- }
- }
-
- else switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_END_OF_FILE:
- {
- (yy_did_buffer_switch_on_eof) = 0;
-
- if ( zconfwrap( ) )
- {
- /* Note: because we've taken care in
- * yy_get_next_buffer() to have set up
- * zconftext, we can now set up
- * yy_c_buf_p so that if some total
- * hoser (like flex itself) wants to
- * call the scanner after we return the
- * YY_NULL, it'll still work - another
- * YY_NULL will get returned.
- */
- (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
-
- yy_act = YY_STATE_EOF(YY_START);
- goto do_action;
- }
-
- else
- {
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
- }
- break;
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) =
- (yytext_ptr) + yy_amount_of_matched_text;
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_match;
-
- case EOB_ACT_LAST_MATCH:
- (yy_c_buf_p) =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
-
- yy_current_state = yy_get_previous_state( );
-
- yy_cp = (yy_c_buf_p);
- yy_bp = (yytext_ptr) + YY_MORE_ADJ;
- goto yy_find_action;
- }
- break;
- }
-
- default:
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--no action found" );
- } /* end of action switch */
- } /* end of scanning one token */
-} /* end of zconflex */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- * EOB_ACT_LAST_MATCH -
- * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- * EOB_ACT_END_OF_FILE - end of file
- */
-static int yy_get_next_buffer (void)
-{
- register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
- register char *source = (yytext_ptr);
- register int number_to_move, i;
- int ret_val;
-
- if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
- YY_FATAL_ERROR(
- "fatal flex scanner internal error--end of buffer missed" );
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
- { /* Don't try to fill the buffer, so this is an EOF. */
- if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
- {
- /* We matched a single character, the EOB, so
- * treat this as a final EOF.
- */
- return EOB_ACT_END_OF_FILE;
- }
-
- else
- {
- /* We matched some text prior to the EOB, first
- * process it.
- */
- return EOB_ACT_LAST_MATCH;
- }
- }
-
- /* Try to read more data. */
-
- /* First move last chars to start of buffer. */
- number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
-
- for ( i = 0; i < number_to_move; ++i )
- *(dest++) = *(source++);
-
- if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
- /* don't do the read, it's not guaranteed to return an EOF,
- * just force an EOF
- */
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
-
- else
- {
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
- while ( num_to_read <= 0 )
- { /* Not enough room in the buffer - grow it. */
-
- /* just a shorter name for the current buffer */
- YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
-
- int yy_c_buf_p_offset =
- (int) ((yy_c_buf_p) - b->yy_ch_buf);
-
- if ( b->yy_is_our_buffer )
- {
- int new_size = b->yy_buf_size * 2;
-
- if ( new_size <= 0 )
- b->yy_buf_size += b->yy_buf_size / 8;
- else
- b->yy_buf_size *= 2;
-
- b->yy_ch_buf = (char *)
- /* Include room in for 2 EOB chars. */
- zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
- }
- else
- /* Can't grow it, we don't own it. */
- b->yy_ch_buf = 0;
-
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR(
- "fatal error - scanner input buffer overflow" );
-
- (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
-
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
-
- }
-
- if ( num_to_read > YY_READ_BUF_SIZE )
- num_to_read = YY_READ_BUF_SIZE;
-
- /* Read in more data. */
- YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- (yy_n_chars), (size_t) num_to_read );
-
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- if ( (yy_n_chars) == 0 )
- {
- if ( number_to_move == YY_MORE_ADJ )
- {
- ret_val = EOB_ACT_END_OF_FILE;
- zconfrestart(zconfin );
- }
-
- else
- {
- ret_val = EOB_ACT_LAST_MATCH;
- YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
- YY_BUFFER_EOF_PENDING;
- }
- }
-
- else
- ret_val = EOB_ACT_CONTINUE_SCAN;
-
- if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
- /* Extend the array by 50%, plus the number we really need. */
- yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
- if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
- }
-
- (yy_n_chars) += number_to_move;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
- YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
-
- (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
- return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
- static yy_state_type yy_get_previous_state (void)
-{
- register yy_state_type yy_current_state;
- register char *yy_cp;
-
- yy_current_state = (yy_start);
-
- for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
- {
- yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)];
- }
-
- return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- * next_state = yy_try_NUL_trans( current_state );
- */
- static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
-{
- register int yy_is_jam;
-
- yy_current_state = yy_nxt[yy_current_state][1];
- yy_is_jam = (yy_current_state <= 0);
-
- return yy_is_jam ? 0 : yy_current_state;
-}
-
- static void yyunput (int c, register char * yy_bp )
-{
- register char *yy_cp;
-
- yy_cp = (yy_c_buf_p);
-
- /* undo effects of setting up zconftext */
- *yy_cp = (yy_hold_char);
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- { /* need to shift things up to make room */
- /* +2 for EOB chars. */
- register int number_to_move = (yy_n_chars) + 2;
- register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2];
- register char *source =
- &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move];
-
- while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
- *--dest = *--source;
-
- yy_cp += (int) (dest - source);
- yy_bp += (int) (dest - source);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars =
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size;
-
- if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 )
- YY_FATAL_ERROR( "flex scanner push-back overflow" );
- }
-
- *--yy_cp = (char) c;
-
- (yytext_ptr) = yy_bp;
- (yy_hold_char) = *yy_cp;
- (yy_c_buf_p) = yy_cp;
-}
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
- static int yyinput (void)
-#else
- static int input (void)
-#endif
-
-{
- int c;
-
- *(yy_c_buf_p) = (yy_hold_char);
-
- if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
- {
- /* yy_c_buf_p now points to the character we want to return.
- * If this occurs *before* the EOB characters, then it's a
- * valid NUL; if not, then we've hit the end of the buffer.
- */
- if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
- /* This was really a NUL. */
- *(yy_c_buf_p) = '\0';
-
- else
- { /* need more input */
- int offset = (yy_c_buf_p) - (yytext_ptr);
- ++(yy_c_buf_p);
-
- switch ( yy_get_next_buffer( ) )
- {
- case EOB_ACT_LAST_MATCH:
- /* This happens because yy_g_n_b()
- * sees that we've accumulated a
- * token and flags that we need to
- * try matching the token before
- * proceeding. But for input(),
- * there's no matching to consider.
- * So convert the EOB_ACT_LAST_MATCH
- * to EOB_ACT_END_OF_FILE.
- */
-
- /* Reset buffer status. */
- zconfrestart(zconfin );
-
- /*FALLTHROUGH*/
-
- case EOB_ACT_END_OF_FILE:
- {
- if ( zconfwrap( ) )
- return EOF;
-
- if ( ! (yy_did_buffer_switch_on_eof) )
- YY_NEW_FILE;
-#ifdef __cplusplus
- return yyinput();
-#else
- return input();
-#endif
- }
-
- case EOB_ACT_CONTINUE_SCAN:
- (yy_c_buf_p) = (yytext_ptr) + offset;
- break;
- }
- }
- }
-
- c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
- *(yy_c_buf_p) = '\0'; /* preserve zconftext */
- (yy_hold_char) = *++(yy_c_buf_p);
-
- return c;
-}
-#endif /* ifndef YY_NO_INPUT */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- *
- * @note This function does not reset the start condition to @c INITIAL .
- */
- void zconfrestart (FILE * input_file )
-{
-
- if ( ! YY_CURRENT_BUFFER ){
- zconfensure_buffer_stack ();
- YY_CURRENT_BUFFER_LVALUE =
- zconf_create_buffer(zconfin,YY_BUF_SIZE );
- }
-
- zconf_init_buffer(YY_CURRENT_BUFFER,input_file );
- zconf_load_buffer_state( );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- *
- */
- void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer )
-{
-
- /* TODO. We should be able to replace this entire function body
- * with
- * zconfpop_buffer_state();
- * zconfpush_buffer_state(new_buffer);
- */
- zconfensure_buffer_stack ();
- if ( YY_CURRENT_BUFFER == new_buffer )
- return;
-
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
- zconf_load_buffer_state( );
-
- /* We don't actually know whether we did this switch during
- * EOF (zconfwrap()) processing, but the only time this flag
- * is looked at is after zconfwrap() is called, so it's safe
- * to go ahead and always set it.
- */
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-static void zconf_load_buffer_state (void)
-{
- (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
- (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
- zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
- (yy_hold_char) = *(yy_c_buf_p);
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- *
- * @return the allocated buffer state.
- */
- YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size )
-{
- YY_BUFFER_STATE b;
-
- b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
-
- b->yy_buf_size = size;
-
- /* yy_ch_buf has to be 2 characters longer than the size given because
- * we need to put in 2 end-of-buffer characters.
- */
- b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 );
- if ( ! b->yy_ch_buf )
- YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" );
-
- b->yy_is_our_buffer = 1;
-
- zconf_init_buffer(b,file );
-
- return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with zconf_create_buffer()
- *
- */
- void zconf_delete_buffer (YY_BUFFER_STATE b )
-{
-
- if ( ! b )
- return;
-
- if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
- YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
- if ( b->yy_is_our_buffer )
- zconffree((void *) b->yy_ch_buf );
-
- zconffree((void *) b );
-}
-
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a zconfrestart() or at EOF.
- */
- static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file )
-
-{
- int oerrno = errno;
-
- zconf_flush_buffer(b );
-
- b->yy_input_file = file;
- b->yy_fill_buffer = 1;
-
- /* If b is the current buffer, then zconf_init_buffer was _probably_
- * called from zconfrestart() or through yy_get_next_buffer.
- * In that case, we don't want to reset the lineno or column.
- */
- if (b != YY_CURRENT_BUFFER){
- b->yy_bs_lineno = 1;
- b->yy_bs_column = 0;
- }
-
- b->yy_is_interactive = 0;
-
- errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- *
- */
- void zconf_flush_buffer (YY_BUFFER_STATE b )
-{
- if ( ! b )
- return;
-
- b->yy_n_chars = 0;
-
- /* We always need two end-of-buffer characters. The first causes
- * a transition to the end-of-buffer state. The second causes
- * a jam in that state.
- */
- b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
- b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
- b->yy_buf_pos = &b->yy_ch_buf[0];
-
- b->yy_at_bol = 1;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- if ( b == YY_CURRENT_BUFFER )
- zconf_load_buffer_state( );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- * the current state. This function will allocate the stack
- * if necessary.
- * @param new_buffer The new state.
- *
- */
-void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer )
-{
- if (new_buffer == NULL)
- return;
-
- zconfensure_buffer_stack();
-
- /* This block is copied from zconf_switch_to_buffer. */
- if ( YY_CURRENT_BUFFER )
- {
- /* Flush out information for old buffer. */
- *(yy_c_buf_p) = (yy_hold_char);
- YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
- YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
- }
-
- /* Only push if top exists. Otherwise, replace top. */
- if (YY_CURRENT_BUFFER)
- (yy_buffer_stack_top)++;
- YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
- /* copied from zconf_switch_to_buffer. */
- zconf_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- * The next element becomes the new top.
- *
- */
-void zconfpop_buffer_state (void)
-{
- if (!YY_CURRENT_BUFFER)
- return;
-
- zconf_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- if ((yy_buffer_stack_top) > 0)
- --(yy_buffer_stack_top);
-
- if (YY_CURRENT_BUFFER) {
- zconf_load_buffer_state( );
- (yy_did_buffer_switch_on_eof) = 1;
- }
-}
-
-/* Allocates the stack if it does not exist.
- * Guarantees space for at least one push.
- */
-static void zconfensure_buffer_stack (void)
-{
- int num_to_alloc;
-
- if (!(yy_buffer_stack)) {
-
- /* First allocation is just for 2 elements, since we don't know if this
- * scanner will even need a stack. We use 2 instead of 1 to avoid an
- * immediate realloc on the next call.
- */
- num_to_alloc = 1;
- (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc
- (num_to_alloc * sizeof(struct yy_buffer_state*)
- );
- if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
-
- memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
- (yy_buffer_stack_max) = num_to_alloc;
- (yy_buffer_stack_top) = 0;
- return;
- }
-
- if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
-
- /* Increase the buffer to prepare for a possible push. */
- int grow_size = 8 /* arbitrary grow size */;
-
- num_to_alloc = (yy_buffer_stack_max) + grow_size;
- (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc
- ((yy_buffer_stack),
- num_to_alloc * sizeof(struct yy_buffer_state*)
- );
- if ( ! (yy_buffer_stack) )
- YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" );
-
- /* zero only the new slots.*/
- memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
- (yy_buffer_stack_max) = num_to_alloc;
- }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size )
-{
- YY_BUFFER_STATE b;
-
- if ( size < 2 ||
- base[size-2] != YY_END_OF_BUFFER_CHAR ||
- base[size-1] != YY_END_OF_BUFFER_CHAR )
- /* They forgot to leave room for the EOB's. */
- return 0;
-
- b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) );
- if ( ! b )
- YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" );
-
- b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
- b->yy_buf_pos = b->yy_ch_buf = base;
- b->yy_is_our_buffer = 0;
- b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
- b->yy_is_interactive = 0;
- b->yy_at_bol = 1;
- b->yy_fill_buffer = 0;
- b->yy_buffer_status = YY_BUFFER_NEW;
-
- zconf_switch_to_buffer(b );
-
- return b;
-}
-
-/** Setup the input buffer state to scan a string. The next call to zconflex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- *
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- * zconf_scan_bytes() instead.
- */
-YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr )
-{
-
- return zconf_scan_bytes(yystr,strlen(yystr) );
-}
-
-/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will
- * scan from a @e copy of @a bytes.
- * @param bytes the byte buffer to scan
- * @param len the number of bytes in the buffer pointed to by @a bytes.
- *
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len )
-{
- YY_BUFFER_STATE b;
- char *buf;
- yy_size_t n;
- int i;
-
- /* Get memory for full buffer, including space for trailing EOB's. */
- n = _yybytes_len + 2;
- buf = (char *) zconfalloc(n );
- if ( ! buf )
- YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" );
-
- for ( i = 0; i < _yybytes_len; ++i )
- buf[i] = yybytes[i];
-
- buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
- b = zconf_scan_buffer(buf,n );
- if ( ! b )
- YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" );
-
- /* It's okay to grow etc. this buffer, and we should throw it
- * away when we're done.
- */
- b->yy_is_our_buffer = 1;
-
- return b;
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-static void yy_fatal_error (yyconst char* msg )
-{
- (void) fprintf( stderr, "%s\n", msg );
- exit( YY_EXIT_FAILURE );
-}
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
- do \
- { \
- /* Undo effects of setting up zconftext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
- zconftext[zconfleng] = (yy_hold_char); \
- (yy_c_buf_p) = zconftext + yyless_macro_arg; \
- (yy_hold_char) = *(yy_c_buf_p); \
- *(yy_c_buf_p) = '\0'; \
- zconfleng = yyless_macro_arg; \
- } \
- while ( 0 )
-
-/* Accessor methods (get/set functions) to struct members. */
-
-/** Get the current line number.
- *
- */
-int zconfget_lineno (void)
-{
-
- return zconflineno;
-}
-
-/** Get the input stream.
- *
- */
-FILE *zconfget_in (void)
-{
- return zconfin;
-}
-
-/** Get the output stream.
- *
- */
-FILE *zconfget_out (void)
-{
- return zconfout;
-}
-
-/** Get the length of the current token.
- *
- */
-int zconfget_leng (void)
-{
- return zconfleng;
-}
-
-/** Get the current token.
- *
- */
-
-char *zconfget_text (void)
-{
- return zconftext;
-}
-
-/** Set the current line number.
- * @param line_number
- *
- */
-void zconfset_lineno (int line_number )
-{
-
- zconflineno = line_number;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- *
- * @see zconf_switch_to_buffer
- */
-void zconfset_in (FILE * in_str )
-{
- zconfin = in_str ;
-}
-
-void zconfset_out (FILE * out_str )
-{
- zconfout = out_str ;
-}
-
-int zconfget_debug (void)
-{
- return zconf_flex_debug;
-}
-
-void zconfset_debug (int bdebug )
-{
- zconf_flex_debug = bdebug ;
-}
-
-static int yy_init_globals (void)
-{
- /* Initialization is the same as for the non-reentrant scanner.
- * This function is called from zconflex_destroy(), so don't allocate here.
- */
-
- (yy_buffer_stack) = 0;
- (yy_buffer_stack_top) = 0;
- (yy_buffer_stack_max) = 0;
- (yy_c_buf_p) = (char *) 0;
- (yy_init) = 0;
- (yy_start) = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
- zconfin = stdin;
- zconfout = stdout;
-#else
- zconfin = (FILE *) 0;
- zconfout = (FILE *) 0;
-#endif
-
- /* For future reference: Set errno on error, since we are called by
- * zconflex_init()
- */
- return 0;
-}
-
-/* zconflex_destroy is for both reentrant and non-reentrant scanners. */
-int zconflex_destroy (void)
-{
-
- /* Pop the buffer stack, destroying each element. */
- while(YY_CURRENT_BUFFER){
- zconf_delete_buffer(YY_CURRENT_BUFFER );
- YY_CURRENT_BUFFER_LVALUE = NULL;
- zconfpop_buffer_state();
- }
-
- /* Destroy the stack itself. */
- zconffree((yy_buffer_stack) );
- (yy_buffer_stack) = NULL;
-
- /* Reset the globals. This is important in a non-reentrant scanner so the next time
- * zconflex() is called, initialization will occur. */
- yy_init_globals( );
-
- return 0;
-}
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
-{
- register int i;
- for ( i = 0; i < n; ++i )
- s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s )
-{
- register int n;
- for ( n = 0; s[n]; ++n )
- ;
-
- return n;
-}
-#endif
-
-void *zconfalloc (yy_size_t size )
-{
- return (void *) malloc( size );
-}
-
-void *zconfrealloc (void * ptr, yy_size_t size )
-{
- /* The cast to (char *) in the following accommodates both
- * implementations that use char* generic pointers, and those
- * that use void* generic pointers. It works with the latter
- * because both ANSI C and C++ allow castless assignment from
- * any pointer type to void*, and deal with argument conversions
- * as though doing an assignment.
- */
- return (void *) realloc( (char *) ptr, size );
-}
-
-void zconffree (void * ptr )
-{
- free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
-
-void zconf_starthelp(void)
-{
- new_string();
- last_ts = first_ts = 0;
- BEGIN(HELP);
-}
-
-static void zconf_endhelp(void)
-{
- zconflval.string = text;
- BEGIN(INITIAL);
-}
-
-/*
- * Try to open specified file with following names:
- * ./name
- * $(srctree)/name
- * The latter is used when srctree is separate from objtree
- * when compiling the kernel.
- * Return NULL if file is not found.
- */
-FILE *zconf_fopen(const char *name)
-{
- char *env, fullname[PATH_MAX+1];
- FILE *f;
-
- f = fopen(name, "r");
- if (!f && name != NULL && name[0] != '/') {
- env = getenv(SRCTREE);
- if (env) {
- sprintf(fullname, "%s/%s", env, name);
- f = fopen(fullname, "r");
- }
- }
- return f;
-}
-
-void zconf_initscan(const char *name)
-{
- zconfin = zconf_fopen(name);
- if (!zconfin) {
- printf("can't find file %s\n", name);
- exit(1);
- }
-
- current_buf = malloc(sizeof(*current_buf));
- memset(current_buf, 0, sizeof(*current_buf));
-
- current_file = file_lookup(name);
- current_file->lineno = 1;
-}
-
-void zconf_nextfile(const char *name)
-{
- struct file *iter;
- struct file *file = file_lookup(name);
- struct buffer *buf = malloc(sizeof(*buf));
- memset(buf, 0, sizeof(*buf));
-
- current_buf->state = YY_CURRENT_BUFFER;
- zconfin = zconf_fopen(file->name);
- if (!zconfin) {
- printf("%s:%d: can't open file \"%s\"\n",
- zconf_curname(), zconf_lineno(), file->name);
- exit(1);
- }
- zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE));
- buf->parent = current_buf;
- current_buf = buf;
-
- for (iter = current_file->parent; iter; iter = iter->parent ) {
- if (!strcmp(current_file->name,iter->name) ) {
- printf("%s:%d: recursive inclusion detected. "
- "Inclusion path:\n current file : '%s'\n",
- zconf_curname(), zconf_lineno(),
- zconf_curname());
- iter = current_file->parent;
- while (iter && \
- strcmp(iter->name,current_file->name)) {
- printf(" included from: '%s:%d'\n",
- iter->name, iter->lineno-1);
- iter = iter->parent;
- }
- if (iter)
- printf(" included from: '%s:%d'\n",
- iter->name, iter->lineno+1);
- exit(1);
- }
- }
- file->lineno = 1;
- file->parent = current_file;
- current_file = file;
-}
-
-static void zconf_endfile(void)
-{
- struct buffer *parent;
-
- current_file = current_file->parent;
-
- parent = current_buf->parent;
- if (parent) {
- fclose(zconfin);
- zconf_delete_buffer(YY_CURRENT_BUFFER);
- zconf_switch_to_buffer(parent->state);
- }
- free(current_buf);
- current_buf = parent;
-}
-
-int zconf_lineno(void)
-{
- return current_pos.lineno;
-}
-
-const char *zconf_curname(void)
-{
- return current_pos.file ? current_pos.file->name : "<none>";
-}
-
diff --git a/scripts/mk-am35xx-spi-image.c b/scripts/mk-am35xx-spi-image.c
new file mode 100644
index 0000000000..ec311fdd4d
--- /dev/null
+++ b/scripts/mk-am35xx-spi-image.c
@@ -0,0 +1,141 @@
+/*
+ * mk-am35xx-spi-image.c - convert a barebox image for SPI loading on AM35xx
+ *
+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/**
+ * @file
+ * @brief convert a barebox image for SPI loading on AM35xx
+ *
+ * FileName: scripts/mk-am35xx-spi-image.c
+ *
+ * Booting from SPI on an AM35xx (and possibly other TI SOCs) requires
+ * a special format:
+ *
+ * - 32 bit image size in big-endian
+ * - 32 bit load address in big-endian
+ * - binary image converted from little- to big-endian
+ *
+ * This tool converts barebox.bin to the required format.
+ */
+
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <endian.h>
+
+void usage(char *prgname)
+{
+ printf("usage: %s [OPTION] FILE > IMAGE\n"
+ "\n"
+ "options:\n"
+ " -a <address> memory address for the loaded image in SRAM\n",
+ prgname);
+}
+
+int main(int argc, char *argv[])
+{
+ FILE *input;
+ int opt;
+ off_t pos;
+ size_t size;
+ uint32_t addr = 0x40200000;
+ uint32_t temp;
+
+ while((opt = getopt(argc, argv, "a:")) != -1) {
+ switch (opt) {
+ case 'a':
+ addr = strtoul(optarg, NULL, 0);
+ break;
+ }
+ }
+
+ if (optind >= argc) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ input = fopen(argv[optind], "r");
+ if (input == NULL) {
+ perror("fopen");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fseeko(input, 0, SEEK_END) == -1) {
+ perror("fseeko");
+ exit(EXIT_FAILURE);
+ }
+
+ pos = ftello(input);
+ if (pos == -1) {
+ perror("ftello");
+ exit(EXIT_FAILURE);
+ }
+ if (pos % 4) {
+ printf("error: image size must be a multiple of 4 bytes\n");
+ exit(EXIT_FAILURE);
+ }
+ if (pos > 0x100000) {
+ printf("error: image should be smaller than 1 MiB\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (fseeko(input, 0, SEEK_SET) == -1) {
+ perror("fseeko");
+ exit(EXIT_FAILURE);
+ }
+
+ /* image size */
+ temp = htobe32((uint32_t)pos);
+ fwrite(&temp, sizeof(uint32_t), 1, stdout);
+
+ /* memory address */
+ temp = htobe32(addr);
+ fwrite(&temp, sizeof(uint32_t), 1, stdout);
+
+ for (;;) {
+ size = fread(&temp, 1, sizeof(uint32_t), input);
+ if (!size)
+ break;
+ if (size != 4) {
+ perror("fread");
+ exit(EXIT_FAILURE);
+ }
+ temp = htobe32(le32toh(temp));
+ if (fwrite(&temp, 1, sizeof(uint32_t), stdout) != 4) {
+ perror("fwrite");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (fclose(input) != 0) {
+ perror("fclose");
+ exit(EXIT_FAILURE);
+ }
+
+ exit(EXIT_SUCCESS);
+}